SQL :具有动态列值分配的更新语句

Posted

技术标签:

【中文标题】SQL :具有动态列值分配的更新语句【英文标题】:SQL : update statement with dynamic column value assignment 【发布时间】:2009-02-17 12:01:04 【问题描述】:

想象一下下面的 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 的值?我意识到这样做可能会出现性能问题,但我仍然很好奇!有没有更好的选择(不涉及多个更新语句)?

顺便说一句:如果您想知道上述查询(嵌套内表)使用的语法,请参见此处:SQL : Using the target table in an UPDATE statement in a nested FROM clause

【问题讨论】:

请发布您现在在表格中的内容以及您希望看到的结果。 【参考方案1】:
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 

永远不会结束。

【讨论】:

【参考方案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 在UPDATE 语句中支持ORDER BY(这不是标准SQL),您应该这样做,以确保按您想要的顺序更新值。否则 MySQL 不保证特定顺序。

【讨论】:

这也有效!但由于我通过 jdbc 将查询作为单个语句执行,因此我将使用 @Quassnoi's。【参考方案3】:
declare @loop int
select @loop = 1

UPDATE MYTABLE
SET COL1 = @loop,
    @loop = @loop+1
WHERE ID IN (1,2,3,4,5)

【讨论】:

【参考方案4】:

是否有一种聪明的方法可以在每次插入时“重新评估”MAX(COL1) +1 的值?

除非您逐一更新行:(

这适用于 MSSQL,不知道 MySQL,但可能会给你一个想法:

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

【讨论】:

【参考方案5】:

应该在每次插入时重新评估它;大概 COL2 的最大值没有变化。确定不想选择 MAX(COL1)? 再次阅读您的问题,您混淆了插入和更新(现已修复)这两个术语,我被抛出了一个循环。


您正在尝试一次更新多条记录,但让它表现得好像在单独更新每条记录一样。这不会按您的预期工作。

您可以创建一个存储过程来循环遍历每个记录 WHERE ID IN (1,2,3,4,5) 并单独更新。或者,既然您只做 5 行,为什么不直接复制并粘贴该语句五次并将 WHERE 子句更改为 WHERE ID = 1(以及后续行中的 2、3、4、5)。

【讨论】:

“除非你的 SQL 品牌不喜欢它?”我相信 MySQL 必须对 UPDATE 中的嵌套 SELECT 进行双重包装。我认为您的解决方案将为更新中的所有 5 行分配相同的 MAX(COL2) 值 显然是这样,假设原始帖子中的“BTW”链接是正确的。 @lc :回答“作为旁注,您为什么要将 MAX(COL2) 投射到临时表并再次从中选择?”请阅读全文(包括最后的 BTW) 是的,我明白了。请注意“显然如此”和我的编辑。很抱歉错过了第一次(和第二次)。

以上是关于SQL :具有动态列值分配的更新语句的主要内容,如果未能解决你的问题,请参考以下文章

在 Oracle SQL 中生成动态列值

动态修剪列值

具有动态 SQL 语句的 Redshift UDF 函数

是否可以将 SELECT 语句中具有重复列值的记录与 SQL 中的另一条记录合并?

使用动态查询更新表的“n”列值

通过存储过程创建具有动态列的视图