【问题标题】:SQL Server : how to loop through a table applying multi-record updates to another?SQL Server:如何循环一个表,将多记录更新应用到另一个表?
【发布时间】:2015-01-12 14:57:12
【问题描述】:

我希望根据包含更新详细信息的表 Y 更新表 X 中的记录。困难在于

  • 一行 Y 表示更新 X 中指定数量的记录。
  • Y 中可能有多个记录指定对 X 中记录的不同更新,这些记录在它们匹配的字段中是相似的;在这种情况下,更新应该应用于 X 的不相交子集。

假设 X = materials(id, type_id, status, data); Y = material_updates(run_id, type_id, quantity, data)

id 只是一个内部主键字段)

那么我想做的是(相当于)循环一个简单的查询,比如

SELECT * 
FROM material_updates 
WHERE run_id = :run;

对于结果集的每个row,应用类似

UPDATE TOP(row.quantity) materials 
SET data = row.data, status = 1
WHERE status = 0 AND type_id = row.type_id;

(对status 的更改恰好在我要解决的问题中保持不变)

样本数据

materials_update 表:

run_id  type_id quantity    data
   1       1        3         42
   1       2        2         69
   1       2        1        105

更新前的材料表:

type_id status  data
   1       1     17
   1       1     17
   1       0      0
   1       0      0
   1       0      0
   1       0      0
   2       0      0
   2       0      0
   2       0      0
   2       0      0

更新后的材料表:

type_id status  data
   1       1     17
   1       1     17
   1       1     42
   1       1     42
   1       1     42
   1       0      0
   2       1     69
   2       1     69
   2       1    105
   2       0      0

我认为可以使用光标来完成,但这是最好的解决方案,还是有更有效的方法?

【问题讨论】:

  • 这个问题对你来说可能看起来很清楚,但我们对每个问题都不太了解。你能举几个例子吗?
  • @ZoffDino 你的意思是material_updates表的例子,以及操作前后的materials表应该是什么样子的?
  • SQL 中很少需要循环。您可以使用 FROM 子句创建一个 UPDATE 语句,该子句从另一个表中提取所需的数据,以及在公共列上连接源表和目标表
  • @Stewart 是的!清楚地表明您的要求的东西

标签: sql-server tsql


【解决方案1】:

这对于CURSOR (msdn link) 来说是完美的,它允许您逐行迭代查询结果并为每个结果执行操作。

This one here 是一个很好的教程。

这段代码可以解决你的需求:

-- the best fit for this code would be a Stored Procedure with one parameter
-- which is the run_id value you want.

-- error checking omitted for brevity

DECLARE CURSOR theCursor 
FOR SELECT type_id, quantity, data FROM material_updates WHERE run_id = @run_id;

DECLARE @type_id int; -- types should match your material_updates fields
DECLARE @quantity int;
DECLARE @data int;

OPEN theCursor;

FETCH NEXT FROM theCursor INTO @type_id, @quantity, @data;
WHILE @@FETCH_STATUS = 0
BEGIN
    UPDATE TOP(@quantity) materials
    SET data = @data, status = 1
    WHERE status = 0 AND type_id = @type_id;
END;

CLOSE theCursor;
DEALLOCATE theCursor;

另一种解决方案是使用 UPDATE FROM (SO already has info about it),但我不知道如何让它更新特定数量的行。它很可能无法做到这一点。

请注意,您最终得到的数据毫无意义,因为没有 ORDER:您永远不会知道 哪些 行将/已更新。

【讨论】:

  • 没有理由将游标用于如此简单的查询 - 游标很少需要,但它们确实会导致糟糕的性能
  • OP 想要更新精确的行数,我想不出一个可行的 UPDATE FROM 语法
  • 诀窍是限制选定的行,因为 Donal 已经发布了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多