在表格中我有A列和B列。我想使用B的值更新A,然后将B更新为新值。这必须以原子方式完成。
我正在尝试这样的事情
-- Intially A = 1, B = 2
UPDATE T SET A = B, B = 10 WHERE ID = 1;
-- Now A = 2, B = 10
虽然这是有效的,但是我无法找到保证我首先评估A = B并且稍后评估B = 10的文档。
答案 0 :(得分:5)
您可以在SQL标准中找到它,它定义了一般规则。
Oracle确实符合这个标准。
看到这里 - SQL 92:
http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
第393页,“13.9<更新语句:定位>”一章,第6点)
6)在更新之前有效评估< value表达式> 对象行。如果a包含引用 到T列,然后引用它的值 对象行的任何值之前的对象行中的列 更新。
考虑一般更新语法:<
UPDATE ....
SET <object column 1> = <value expression 1>,
<object column 2> = <value expression 2>,
......
<object column N> = <value expression N>;
规则#6表示在更新行中的任何列之前,首先评估右侧的所有表达式。
在评估所有表达式时,只考虑旧行的值(在更新之前)。
答案 1 :(得分:1)
IMO,Oracle和任何其他RDBMS一样,首先将您的数据从您的表中缓存到缓存中然后从缓存的信息中读取,所以我认为当您在SET
的左侧使用字段名称时, RDMBS读取旧数据的值(在任何更改之前)。
答案 2 :(得分:1)
在RDBMS中(与编程语言不同),没有评估顺序,所有这些都是一次性完成的。这就像先将变量设置为先前的值然后使用这些变量:
SET a=b, b=a
只需切换a
和b
。
警告:只有MySQL完全错误,导致两者都设置为相同的b
值,此处您需要一个临时变量,如:
SET temp=b, b=a, a = temp
答案 3 :(得分:0)
SQL标准不保证update语句中的任何顺序。 我建议按所需顺序运行两个更新,以确保它们的顺序正确。
-- Intially A = 1, B = 2
BEGIN TRANSACTION;
UPDATE T SET A = B WHERE ID = 1;
UPDATE T SET B = 10 WHERE ID = 1;
COMMIT TRANSACTION;
-- Now A = 2, B = 10