oracle数据库中update-set-clause中表达式的计算顺序

时间:2015-10-11 10:43:50

标签: sql oracle

在表格中我有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的文档。

我浏览了oracle sql reference of the update statement

4 个答案:

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

只需切换ab

警告:只有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