我目前正在处理一个问题,其中某些字符需要从表中存在的字符串中清除.通常我会使用替换进行简单的UPDATE,但在这种情况下需要删除32个不同的字符.
我已经做了一些环顾四周,我找不到任何很好的解决方案来快速清理表中已经存在的字符串.
我调查过的事情:
>进行一系列嵌套替换
这个解决方案是可行的,但是对于32种不同的替换,它需要一些丑陋的代码或hacky动态sql来构建一系列大量的替换.
> PATINDEX和while循环
如this answer所示,可以模仿一种正则表达式替换,但我正在使用大量数据,所以我甚至不相信改进的解决方案在数据量很大的合理时间内运行.
>递归CTE
我尝试了一个CTE approuch来解决这个问题,但是一旦行数变大,它就不会运行得非常快.
以供参考:
CREATE TABLE #BadChar(
id int IDENTITY(1,1),
badString nvarchar(10),
replaceString nvarchar(10)
);
INSERT INTO #BadChar(badString, replaceString) SELECT 'A', '^';
INSERT INTO #BadChar(badString, replaceString) SELECT 'B', '}';
INSERT INTO #BadChar(badString, replaceString) SELECT 's', '5';
INSERT INTO #BadChar(badString, replaceString) SELECT '-', ' ';
CREATE TABLE #CleanMe(
clean_id int IDENTITY(1,1),
DirtyString nvarchar(20)
);
DECLARE @i int;
SET @i = 0;
WHILE @i < 100000 BEGIN
INSERT INTO #CleanMe(DirtyString) SELECT 'AAAAA';
INSERT INTO #CleanMe(DirtyString) SELECT 'BBBBB';
INSERT INTO #CleanMe(DirtyString) SELECT 'AB-String-BA';
SET @i = @i + 1
END;
WITH FixedString (Step, String, cid) AS (
SELECT 1 AS Step, REPLACE(DirtyString, badString, replaceString), clean_id
FROM #BadChar, #CleanMe
WHERE id = 1
UNION ALL
SELECT Step + 1, REPLACE(String, badString, replaceString), cid
FROM FixedString AS T1
JOIN #BadChar AS T2 ON T1.step + 1 = T2.id
Join #CleanMe AS T3 on T1.cid = t3.clean_id
)
SELECT String FROM FixedString WHERE step = (SELECT MAX(STEP) FROM FixedString);
DROP TABLE #BadChar;
DROP TABLE #CleanMe;
>使用CLR
看起来这是许多人使用的常见解决方案,但我所处的环境并不能让这一点变得非常容易.
还有其他方法可以解决这个问题吗?或者对我已经考虑过的方法有什么改进?
最佳答案 利用
Alan Burstein’s solution的想法,你可以做这样的事情,如果你想硬编码坏/替换字符串.这对于错误/替换字符串也比单个字符更长.
CREATE FUNCTION [dbo].[CleanStringV1]
(
@String nvarchar(4000)
)
RETURNS nvarchar(4000) WITH SCHEMABINDING AS
BEGIN
SELECT @string = REPLACE
(
@string COLLATE Latin1_General_BIN,
badString,
replaceString
)
FROM
(VALUES
('A', '^')
, ('B', '}')
, ('s', '5')
, ('-', ' ')
) t(badString, replaceString)
RETURN @string;
END;
或者,如果你有一个包含坏/替换字符串的表,那么
CREATE FUNCTION [dbo].[CleanStringV2]
(
@String nvarchar(4000)
)
RETURNS nvarchar(4000) AS
BEGIN
SELECT @string = REPLACE
(
@string COLLATE Latin1_General_BIN,
badString,
replaceString
)
FROM BadChar
RETURN @string;
END;
这些是区分大小写的.如果您不区分大小写,可以删除COLLATE位.我做了一些小测试,这些测试并不比嵌套的REPLACE慢得多.带有硬编码字符串的第一个是两者中较快的一个,并且几乎与嵌套的REPLACE一样快.