在这种情况下,是否可以基于集合而不是光标循环?

时间:2019-05-01 16:44:55

标签: sql sql-server

当前代码:

DECLARE thisLoop CURSOR FOR  
SELECT IdOld, IdNew  
FROM @fieldNewOld;  

OPEN thisLoop;  

FETCH NEXT FROM thisLoop INTO @fIdOld, @fIdNew;  
WHILE @@FETCH_STATUS = 0  
BEGIN

UPDATE dbo.mel
      SET melCode = REPLACE(melCode, '_' + CONVERT(varchar(50),@fIdOld), '_' + CONVERT(varchar(50),@fIdNew))
      where fID = (select IdNew from @newForm) and melCode LIKE ('%_'  + CONVERT(varchar(50), @fIdOld) + '%')

    FETCH NEXT FROM thisLoop INTO @fIdOld, @fIdNew 
END;  

CLOSE thisLoop;  
DEALLOCATE thisLoop;

还有更多事情要做,但是基本上我是在复制数据集。 @fieldNewOld包含旧ID和新ID。 dbo.mel中的melCode包含以专有语言编写的代码,可以引用所有旧ID。它将被引用为“ myVar_1234”之类的内容,其中1234将是旧ID之一。复制时,我想用melCode中的新ID替换所有旧ID。

我可以使用上面显示的光标循环来做到这一点,但是当数据集很大时,它会非常慢。我也尝试过下面的代码,但是如果melCode中有多个旧ID,它将尝试多次更新同一行并抛出错误:

MERGE INTO dbo.mel b
   USING @fieldNewOld a
      ON b.fID = (select IdNew from @newForm) and b.melCode LIKE ('%_' + CONVERT(varchar(50), a.IdOld) + '%')
WHEN MATCHED THEN
   UPDATE 
      SET b.melCode = REPLACE(b.melCode, '_' + CONVERT(varchar(50),a.IdOld), '_' + CONVERT(varchar(50),a.IdNew));

是否有任何方法可以以基于集合的方式完成此操作,还是我陷入了游标循环缓慢的问题?

示例数据:

@fieldNewOld

IdOld | IdNew
1234 | 5678
1235 | 5679
1236 | 5680

melCode(所有这些都在一行中)

userok("My variable: " + myVar_1234)
myVar_1234 = "this is a test"
newVar_1236 = "here is some more data"

复制后,我希望melCode看起来像这样:

userok("My variable: " + myVar_5678)
myVar_5678 = "this is a test"
newVar_5680 = "here is some more data"

2 个答案:

答案 0 :(得分:1)

您可以在UPDATE中使用JOIN。

UPDATE m
SET melCode = REPLACE(melCode, '_' + CONVERT(varchar(50),IdOld), '_' + CONVERT(varchar(50),fIdNew))
FROM dbo.mel m
JOIN @fieldNewOld fno ON m.melCode LIKE ('%_'  + CONVERT(varchar(50), IdOld) + '%')
where fID = (select IdNew from @newForm) ;

这似乎在melCode中具有复合值。我的建议是将值分成2个或更多列,并将melCode作为计算列。

答案 1 :(得分:1)

考虑用JOIN更新最终表和表变量:

UPDATE m
SET m.melCode = REPLACE(m.melCode, '_' + CONVERT(varchar(50), f.IdOld), 
                        '_' + CONVERT(varchar(50), f.IdNew))
FROM dbo.mel m
JOIN @fieldNewOld f 
  ON m.melCode LIKE ('%_'  + CONVERT(varchar(50), f.IdOld) + '%')
JOIN @newForm n 
  ON m.fID = n.IdNew 

由于您需要多次更新相同的文本,因此请考虑在fieldNewOld ID中的行数上进行迭代更新来包装上面的内容:

DECLARE @Counter INT
DECLARE @ID_Count INT

SET @Counter = 0
SET @ID_Count = (SELECT COUNT(*) FROM @fieldNewOld)

WHILE @Counter <= @ID_Count

BEGIN
    UPDATE m
    SET m.melCode = REPLACE(m.melCode, '_' + CONVERT(varchar(50), f.IdOld), 
                            '_' + CONVERT(varchar(50), f.IdNew))
    FROM dbo.mel m
    JOIN @fieldNewOld f 
      ON m.melCode LIKE ('%_'  + CONVERT(varchar(50), f.IdOld) + '%')
    JOIN @newForm n 
      ON m.fID = n.IdNew 

    SET @Counter += 1
END

Rextester Demo