SQL 服务器:如何循环 table 将多记录更新应用到另一个?

SQL Server : how to loop through a table applying multi-record updates to another?

我希望根据包含更新详细信息的 table Y 来更新 table 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 table:

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

材料table更新前:

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

材料table更新后:

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

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

这非常适合 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) 但我不知道有什么方法可以让它更新特定数量的行。 它很可能不能这样做。

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