首页 > 解决方案 > 在这种情况下,是否可以基于集合而不是游标循环?

问题描述

当前代码:

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"

标签: sqlsql-server

解决方案


您可以在 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 作为计算列。


推荐阅读