想象一下以下的sql查询:
UPDATE MYTABLE
SET COL2 = (SELECT COL2 + 1 FROM (SELECT MAX(COL2) FROM MYTABLE) AS X)
WHERE ID IN (1,2,3,4,5)
假设在执行更新之前MAX(COL2)为1。
我的意图是,对于ID = 1的更新,COL2更新为'max(COL2)+ 1'(即2),并且对于后续更新'MAX(COL2)+ 1'的重新评估,所以对于ID = 2,COL2 = 3和ID = 3,COL2 = 4等...
实际发生的是,对于所有行(ID = 1,2,3,4,5),COL2的值为2.
是否有一种聪明的方法可以在每次更新时重新评估MAX(COL2)+ 1的值?我意识到这样做可能存在性能问题,但我很好奇!是否有更好的替代方案(不涉及多个更新语句)?
BTW:如果您想知道上述查询使用的语法(嵌套内部表),请参阅此处:SQL : Using the target table in an UPDATE statement in a nested FROM clause
答案 0 :(得分:11)
UPDATE mytable, (
SELECT @loop := MAX(col1)
FROM
mytable
) o
SET col1 = (@loop := @loop + 1)
您在此遇到的内容称为query stability
。
没有查询可以看到自己做出的更改,或以下查询:
UPDATE mytable
SET col1 = col2 + 1
WHERE col1 > col2
永远不会结束。
答案 1 :(得分:2)
以下是我的方式:
SELECT MAX(col2) FROM mytable INTO @max;
UPDATE mytable
SET col2 = @max:=@max+1
WHERE id IN (1,2,3,4,5)
ORDER BY id;
我在MySQL 5.1.30上对此进行了测试,但它确实有效。
我首先设置@max
变量只是因为我发现@ Quassnoi在笛卡尔积中做这件事的伎俩是不必要的,不太可读。
请注意,MySQL在ORDER BY
语句中支持UPDATE
(这不是标准SQL),您应该这样做,以确保按所需顺序更新值。否则MySQL不保证特定订单。
答案 2 :(得分:0)
declare @loop int
select @loop = 1
UPDATE MYTABLE
SET COL1 = @loop,
@loop = @loop+1
WHERE ID IN (1,2,3,4,5)
答案 3 :(得分:0)
是否有一种聪明的方法可以在每次插入时重新评估MAX(COL1)+ 1的值?
除非您逐个更新行:(
这适用于MSSQL,关于MySQL的dunno,但可能会给你一个想法:
DECLARE @Counter int
SELECT @Counter = MAX(COL2) FROM MYTABLE
UPDATE MYTABLE
SET @Counter = @Counter + 1,
COL1 = @Counter
WHERE ID IN (1,2,3,4,5)
编辑:我认为SET语句可以在MSSQL中简化为:
SET @Counter = COL1 = @Counter + 1
答案 4 :(得分:-1)
应该在每次插入时重新评估它;大概COL2的最大值没有变化。您确定不想选择MAX(COL 1 )吗?
再次阅读你的问题,你混淆了术语插入和更新(现在已经修复),我被抛出一个循环。
您尝试一次更新许多记录,但让它表现得好像是单独更新每个记录。这不会像你想要的那样有用。
您可以创建一个存储过程来遍历每个记录WHERE ID IN(1,2,3,4,5)并单独更新。或者,由于您只执行5行,为什么不只是复制并粘贴语句五次并将WHERE子句更改为WHERE ID = 1
(以及后续行中的2,3,4,5)。