【问题标题】:SQL: Replace part of a column on multiple rows based on second tableSQL:根据第二个表替换多行上的部分列
【发布时间】:2011-11-04 16:23:36
【问题描述】:

我有一个表格 (pages),其中包含网页的属性,包括页面内容本身的列,NVARCHAR(MAX) 列。

在该列中,我需要查找并替换一堆文本字符串,并将它们替换为其他文本字符串;这些相关性位于第二个表 (moving) 中,其中包含 oldValuenewValue 列。

所以,例如,如果我从这样的两个表开始:

页表:

ID Content
1  Words words Ancient words
2  Blah blah OutWithTheOld blah
3  Etc etc Useless etc

移动台:

OldValue          NewValue
Ancient           Better
OutWithTheOld     InWithTheNew
Useless           Useful

...我需要一种方法来制作一个像这样离开页面表的替换:

ID Content
1  Words words Better words
2  Blah blah InWithTheNew blah
3  Etc etc Useful etc

pages 表中的给定记录可能需要多次替换,并且无法预测 pages 记录是否没有、一个或许多必要的替换,或者会找到来自 moving.oldvalue 的哪些值并且需要更换。

我使用的是 SQL Server 2008,而且我对它还很陌生。非常感谢您提供的任何帮助!

【问题讨论】:

    标签: sql sql-server-2008 replace multiple-tables


    【解决方案1】:

    这是一个使用 CTE 的单语句非游标方法:

    WITH CTE(iteration, page_id, content) AS (
        SELECT
            0,
            P.page_id,
            REPLACE(P.content, M1.old_value, M1.new_value)
        FROM
            Pages P
        INNER JOIN Moving M1 ON
            P.content LIKE '%' + M1.old_value + '%'
        WHERE
            NOT EXISTS (SELECT * FROM Moving M2 WHERE P.content LIKE '%' + M2.old_value + '%' AND M2.moving_id < M1.moving_id)
        UNION ALL
        SELECT
            CTE.iteration + 1,
            CTE.page_id,
            REPLACE(CTE.content, M3.old_value, M3.new_value)
        FROM
            CTE
        INNER JOIN Moving M3 ON
            CTE.content LIKE '%' + M3.old_value + '%'
        WHERE
            NOT EXISTS (SELECT * FROM Moving M4 WHERE CTE.content LIKE '%' + M4.old_value + '%' AND M4.moving_id < M3.moving_id)
    )
    UPDATE P2
    SET
        content = CTE1.content
    FROM
        Pages P2
    INNER JOIN CTE CTE1 ON
        CTE1.page_id = P2.page_id AND
        NOT EXISTS (SELECT * FROM CTE CTE2 WHERE page_id = P2.page_id AND CTE2.iteration > CTE1.iteration)
    

    【讨论】:

    • +1,也在考虑递归 CTE,但与 row_number() 结合使用。
    【解决方案2】:

    试试这个

    DECLARE @OldV NVARCHAR(32)    -- Adjust for your field sizes in MOVING
    DECLARE @NEWV NVARCHAR(32)
    
    DECLARE db_cursor CURSOR FOR  
    SELECT *
    FROM Moving
    
    OPEN db_cursor   
    FETCH NEXT FROM db_cursor INTO @OldV,@newV
    
    WHILE @@FETCH_STATUS = 0   
    BEGIN   
        UPDATE Pages SET content=REPLACE(content,@oldV,@NewV)
          WHERE content LIKE '%'+@OldV+'%'
           FETCH NEXT FROM db_cursor INTO @oldV,@NewV
    END   
    
    CLOSE db_cursor   
    DEALLOCATE db_cursor
    

    虽然我通常不喜欢光标,但这应该可以解决您的问题

    【讨论】:

    • 哇!完全击败了我。除了变量名,我的代码看起来几乎和你的一模一样!
    猜你喜欢
    • 2023-01-26
    • 1970-01-01
    • 1970-01-01
    • 2013-05-05
    • 1970-01-01
    • 2023-03-29
    • 2019-05-05
    • 1970-01-01
    • 2012-08-07
    相关资源
    最近更新 更多