有效清理表格中的字符串

时间:2017-07-24 20:17:36

标签: sql-server tsql

我目前正在处理一个问题,其中某些字符需要从表中存在的字符串中清除。通常情况下,我会使用替换进行简单的UPDATE,但在这种情况下,需要删除32个不同的字符。

我已经做了一些环顾四周,我找不到任何很好的解决方案来快速清理表格中已经存在的字符串。

我已经研究过的事情:

  1. 进行一系列嵌套替换

    这个解决方案是可行的,但对于32种不同的替换,它需要一些丑陋的代码或hacky动态sql来构建一系列大量的替换。

  2. PATINDEX和while循环

    this answer所示,可以模仿一种正则表达式替换,但我处理大量数据,所以我甚至不相信改进的解决方案可以运行数据量很大时的合理时间。

  3. 递归CTE

    我尝试了一个CTE approuch来解决这个问题,但是一旦行数变大,它就不会非常快地运行。

  4. 供参考:

    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;
    
    1. 使用CLR

      这似乎是许多人使用的常见解决方案,但我所处的环境并不能让这个很容易实现。

    2. 还有其他方法可以解决这个问题吗?或者对我已经考虑过的方法进行了哪些改进?

1 个答案:

答案 0 :(得分:1)

利用Alan Burstein's solution的想法,你可以做这样的事情,如果你想硬编码坏/替换字符串。这对于错误/替换字符串也比单个字符更长。

string destination = Path.Combine(f.DirectoryName, string.Format("{0}.{1}", i, type));
if (!File.Exists(destination))
{
    File.Move(f.FullName, destination);
    i++;  // Unclear if you want this to increment every time or just when moving
}

或者,如果你有一个包含坏/替换字符串的表,那么

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;

这些区分大小写。如果您不区分大小写,可以删除COLLATE位。我做了一些小测试,这些测试并不比嵌套的REPLACE慢得多。带有硬编码字符串的第一个是两者中较快的一个,并且几乎与嵌套的REPLACE一样快。