如何使用 while 循环更新行?

Posted

技术标签:

【中文标题】如何使用 while 循环更新行?【英文标题】:How do I update rows using while loop? 【发布时间】:2021-12-28 14:16:01 【问题描述】:

我正在尝试在 while 循环中更新更新查询所在的 SQL 行。

DECLARE @Sayac INT
SET @Sayac= (select count(ABBREVIATION) from [MSTR_MD].[dbo].[v_OpcoGeneral_UserList])
WHILE (@Sayac>0)
BEGIN
    PRINT @Sayac;
    (select ABBREVIATION FROM  [MSTR_MD].[dbo].[v_OpcoGeneral_UserList] WHERE [MSTR_MD].[dbo].[v_OpcoGeneral_UserList].ID = @Sayac)
 UPDATE [dwh].[dbo].[opco_securty]
 SET opco_general = REPLACE(opco_general, (select ABBREVIATION FROM  [MSTR_MD].[dbo].[v_OpcoGeneral_UserList] WHERE [MSTR_MD].[dbo].[v_OpcoGeneral_UserList].ID = @Sayac), '')
    SET @Sayac = @Sayac - 1

END

但是在这个查询中,它没有按预期工作。我猜 while 循环不像编程语言那样被编译。你能推荐一个解决方案吗?谢谢!

例如,如果从视图中接收到“Ugurcan.Kaya”,则从 opco_securty 表的 opco_general(文本)列中删除“Ugurcan.Kaya”。

【问题讨论】:

预期的逻辑看起来很奇怪。为什么要将计数与 id 列进行比较?这感觉像是一个错误。你能澄清问题中的要求吗? 我正在接收来自 [MSTR_MD].[dbo].[v_OpcoGeneral_UserList] 的用户 ID,并希望替换 opco_security 表中检索到的用户 ID 所在的文本。 基本上例如,如果从视图中接收到“Ugurcan.Kaya”,则从 opco_securty 表的 opco_general 列中删除“Ugurcan.Kaya”。 请用最小的可重现测试用例更新问题。但是您正在使用 COUNT 与用户 ID 进行比较。这似乎是一个错误。 您最好向我们展示您在这里实际想要实现的目标。 【参考方案1】:

我认为你可以在没有循环的情况下使用递归 CTE 做你想做的事情。我从这篇文章中借用了这个想法Multiple replacements in string in single Update Statement in SQL server 2005

我对其进行了安排,以便我相信它适用于您的用例。第一个 CTE 使用递归继续应用替换,直到不再存在匹配。

第二个 CTE 用于标识每个发生的递归替换的 row_number。我们感兴趣的 row_number 是 securty 表中每个字符串的最高 row_number,因为它将包含所有必需的替换。

最后,我们运行一条更新语句,用适当的替换字符串更新securty 表中的每条记录。

这是我编写的用于完成这项工作的代码,带有示例数据和表格:

CREATE TABLE UserList(
  id int,
  abbr varchar(25)
);

CREATE TABLE securty(
  id int,
  genrl varchar(250)
);

INSERT INTO UserList(id, abbr)
VALUES(1, 'Ugurcan.Kaya');

INSERT INTO UserList(id, abbr)
VALUES(2, 'User5');

INSERT INTO UserList(id, abbr)
VALUES(3, 'User6');

INSERT INTO securty(id, genrl)
VALUES(1, 'User1-User2-Ugurcan.Kaya-Lorum-User5-User16-User17');

INSERT INTO securty(id, genrl)
VALUES(2, 'User5-Ugurcan.Kaya-Lorum-User5-User16-User17');

;With Replacements as (
    SELECT
        s.id, s.genrl, 0 AS repcount
    FROM
        securty AS s
    UNION ALL
    SELECT
      rs.id, CAST(REPLACE(genrl, ul.abbr, '') AS VARCHAR(250)),rs.repcount+1
    FROM
        Replacements rs
    JOIN
        UserList ul ON CHARINDEX(ul.abbr,rs.genrl) > 0
),
Final_Replacements AS (
  SELECT
    rs.id, rs.genrl, ROW_NUMBER() OVER (PARTITION BY rs.id ORDER BY rs.repcount DESC) AS rn
  FROM
    replacements AS rs
)
UPDATE s
SET s.genrl = fs.genrl
FROM securty AS s
JOIN Final_Replacements AS fs
  ON fs.id = s.id AND fs.rn = 1

我还创建了一个 sqlfiddle 供您试用:http://sqlfiddle.com/#!18/904e0/1/0

【讨论】:

【参考方案2】:

The fiddle

也许这将有助于理解在UPDATE 语句中将一组替换模式应用于目标表的一种方法。

澄清一下,REPLACE 将替换字符串中所有匹配的匹配项,如上一个示例字符串中所示...'6this is XYZ another XYZ test' 已更新为 '6this is another test'

来自 t-sql 文档:

替换 (Transact-SQL)

用另一个字符串值替换所有出现的指定字符串值。

SQL:

UPDATE test
   SET test.data = REPLACE(data, pattern, '')
  FROM test
  JOIN abbrev
    ON test.data LIKE CONCAT('%', pattern, '%')
;

设置:

CREATE TABLE test ( id int, data varchar(40) );

INSERT INTO test VALUES
    ( 1, '1this is a NameToRemove test' )
  , ( 2, '2this is a NameToNotRemove test' )
  , ( 3, '3this is another NameXToRemove test' )
  , ( 4, '4this is another NameXToRemove test' )
  , ( 5, '5this is another NameXToRemove test' )
  , ( 6, '6this is XYZ another XYZ test' )
;

CREATE TABLE abbrev ( id int, pattern varchar(20) );
INSERT INTO abbrev VALUES
    ( 1, 'NameToRemove' )
  , ( 2, 'NameXToRemove' )
  , ( 3, 'NameZToRemove' )
  , ( 4, 'XYZ' )
;

数据:

id data
1 1this is a NameToRemove test
2 2this is a NameToNotRemove test
3 3this is another NameXToRemove test
4 4this is another NameXToRemove test
5 5this is another NameXToRemove test
6 6this is XYZ another XYZ test

结果:

id data
1 1this is a test
2 2this is a NameToNotRemove test
3 3this is another test
4 4this is another test
5 5this is another test
6 6this is another test

【讨论】:

这确实假设一行不能有多个缩写。 没错。这只是一个例子。如果问题数据中未发现其他要求,则可以使用其他略有不同的方法。 @Larnu 实际上,REPLACE 确实处理替换字符串中所有匹配的模式,至少在某些情况下是这样。我会更新测试用例。 但是会出现多个不同替换的问题。 db<>fiddle 显示多个匹配项会发生什么。

以上是关于如何使用 while 循环更新行?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 while 循环内更新 api 调用?

如何仅使用行和固定数量的列进行 for 循环?

如何使用 tkinter 事件“继续”或暂停不同的 while 循环?

如何在 React 的 while 循环中更新状态

如何通过命令行参数批量执行while循环

如何在这个 pyqt5 窗口中使用 while 循环