SQL Server:如何循环遍历一个表,将多记录更新应用到另一个表?

Ste*_*art 0 t-sql sql-server

我希望根据包含更新详细信息的表 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;
Run Code Online (Sandbox Code Playgroud)

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

UPDATE TOP(row.quantity) materials 
SET data = row.data, status = 1
WHERE status = 0 AND type_id = row.type_id;
Run Code Online (Sandbox Code Playgroud)

status(在我试图解决的问题中,的变化恰好是恒定的)

样本数据

材料_更新表:

run_id  type_id quantity    data
   1       1        3         42
   1       2        2         69
   1       2        1        105
Run Code Online (Sandbox Code Playgroud)

更新前的材料表:

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
Run Code Online (Sandbox Code Playgroud)

更新后的材料表:

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
Run Code Online (Sandbox Code Playgroud)

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

Ale*_*lex 5

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

是一个关于它的很好的教程。

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

-- 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;
Run Code Online (Sandbox Code Playgroud)

另一个解决方案是使用UPDATE FROM (所以已经有有关它的信息),但我不知道有什么方法可以让它更新特定数量的行。它很可能无法做到这一点。

但请注意,您最终得到的数据没有任何意义,因为没有顺序:您永远不会知道哪些行将被更新/已经被更新。