SQL: Replace part of a column on multiple rows based on second table

烈酒焚心 提交于 2019-12-10 15:12:48

问题


I have a table (pages) that holds properties for web pages, including a column for the page content itself, an NVARCHAR(MAX) column.

Within that column, I need to find and replace a bunch of text strings and replace them with other text strings; these correlations are in a second table (moving), with an oldValue and newValue column.

So, for example, if I'm starting with the two tables like this:

pages table:

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

moving table:

OldValue          NewValue
Ancient           Better
OutWithTheOld     InWithTheNew
Useless           Useful

...I need a way of making a Replace that leaves the pages table like this:

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

It is possible that a given record in the pages table will need multiple replacements, and there's no way of predicting whether a pages record will have none, one, or many necessary replacements, or which values from moving.oldvalue will be found and need to be replaced.

I'm using SQL Server 2008, and I'm fairly new to it. Thanks so much in advance for any help you can give!


回答1:


Here's a single-statement, non-cursor method which makes use of a 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)



回答2:


Try this

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

Although I generally don't like cursors, this should do the trick for you



来源:https://stackoverflow.com/questions/7207727/sql-replace-part-of-a-column-on-multiple-rows-based-on-second-table

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!