带JOIN的UPDATE仅更新目标列一次

时间:2017-12-14 22:03:46

标签: sql-server tsql

我需要在nvarchar(max)列中替换多个子字符串。子字符串列表和相应的替换值位于单独的表中。当我使用UPDATE运行JOIN语句时,如果我有多个子字符串要替换目标表中的每一行,则替换只发生一次。

以下是说明问题的示例代码,请注意,对于id=1rev=1,我在目标表中有两个要替换的值:

CREATE TABLE dbo.replacements
  (
     id          INT NOT NULL,
     rev         INT NOT NULL,
     target      NVARCHAR(50) NOT NULL,
     replacement NVARCHAR(50) NOT NULL,
  )
go

INSERT INTO dbo.replacements VALUES (1, 1, 'abc', '123');
INSERT INTO dbo.replacements VALUES (1, 1, 'xyz', '789');
INSERT INTO dbo.replacements VALUES (2, 1, 'jkf', '321');
go

CREATE TABLE dbo.destination
  (
     id          INT NOT NULL,
     rev         INT NOT NULL,
     description NVARCHAR(max) NOT NULL
  )
go

INSERT INTO dbo.destination VALUES (1, 1, 'These two strings abc and xyz are to be replaced');
INSERT INTO dbo.destination VALUES (2, 1, 'This text jkf is to be replaced');
go

SELECT *
FROM   dbo.replacements m
       INNER JOIN dbo.destination d ON m.id = d.id AND m.rev = d.rev

UPDATE d
SET    d.description = Replace(d.description, m.target, m.replacement)
FROM   dbo.destination d 
       INNER JOIN dbo.replacements m ON m.id = d.id AND m.rev = d.rev

SELECT *
FROM   dbo.replacements m
       INNER JOIN dbo.destination d ON m.id = d.id AND m.rev = d.rev 

预计第1行的值为'These two strings 123 and 789 are to be replaced',但替换的实际结果为:

id          rev         description
----------- ----------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1           1           These two strings 123 and xyz are to be replaced
1           1           These two strings 123 and xyz are to be replaced
2           1           This text 321 is to be replaced

非常感谢任何建议。

修改

同一行可能有2个以上的替换。

1 个答案:

答案 0 :(得分:1)

我没有在优化和清洁方面花费太多时间,但我会做嵌套替换,并添加另一个连接:

CREATE TABLE #replacements
  (
     id          INT NOT NULL,
     rev         INT NOT NULL,
     target      NVARCHAR(50) NOT NULL,
     replacement NVARCHAR(50) NOT NULL,
  )
go

INSERT INTO #replacements VALUES (1, 1, 'abc', '123');
INSERT INTO #replacements VALUES (1, 1, 'xyz', '789');
INSERT INTO #replacements VALUES (2, 1, 'jkf', '321');
go

CREATE TABLE #destination
  (
     id          INT NOT NULL,
     rev         INT NOT NULL,
     description NVARCHAR(max) NOT NULL
  )
go

INSERT INTO #destination VALUES (1, 1, 'These two strings abc and xyz are to be replaced');
INSERT INTO #destination VALUES (2, 1, 'This text jkf is to be replaced');
go

SELECT *
FROM   #replacements m
       INNER JOIN #destination d ON m.id = d.id AND m.rev = d.rev

UPDATE d
SET    d.description = Replace(REPLACE(d.description, m.target, m.replacement), m2.target, m2.replacement)
FROM   #replacements m
       INNER JOIN #destination d ON m.id = d.id AND m.rev = d.rev
       INNER JOIN #replacements m2 ON m2.id = d.id AND m2.id = d.rev
WHERE m.target <> m2.target

SELECT *
FROM   #replacements m
       INNER JOIN #destination d ON m.id = d.id AND m.rev = d.rev