sql-server – 高效清理表中的字符串

我目前正在处理一个问题,其中某些字符需要从表中存在的字符串中清除.通常我会使用替换进行简单的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一样快.

点赞