SQL:具有动态列值赋值的update语句

时间:2009-02-17 12:01:04

标签: mysql sql sql-update

想象一下以下的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

5 个答案:

答案 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)。