2017-07-24 100 views
4

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

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

事情我已经看着:

  1. 做一系列嵌套内容替换

    的该解决方案是做,能干,但对32种不同取代它需要一些既丑陋的代码,或者哈克动态的sql来构建一个巨大的系列替换。

  2. PATINDEX和while循环

    this answer看到它可以模仿一种正则表达式替换,但我有很多数据的工作,所以我很犹豫,甚至改进方案信任当数据量很大时,在合理的时间内运行。

  3. 递归的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

    看起来这是一个通用的解决方案很多人都用,但环境我“进来并不是一件容易的事。

  • 有没有其他方法可以解决这个问题?或者我已经研究过的方法有什么改进?

    +3

    什么版本的SQL Server?在极不可能的情况下,你在2017年也有['Translate'](https://docs.microsoft.com/en-us/sql/t-sql/functions/translate-transact-sql),尽管这是只是语法糖嵌套取代。 –

    +0

    您可以将数据提取到某个ETL工具,并在那里执行操作,而不会高度依赖数据库功能。例如,调查使用Community Edition免费的Pentaho数据集成。 –

    +4

    嵌套替换速度非常快。为了上帝的缘故,不要为了简单的事情而启动CLR或ETL。做嵌套替换,确保它在语法上有点难看,但不是什么大不了的。 –

    回答

    1

    利用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一样快。