使用Oracle中的单个更新语句更新两个从属列

时间:2015-06-23 05:30:56

标签: sql oracle sql-update

我创建了这个表:

Create table Vars(A number, B number, C number);

然后,我插入了一个新行,其中只有第一列(即A)具有值:

Insert Into Vars(A) values (2);

现在,我想创建一个更新语句,修改列BC的值,如下所示:

B = A * A

C = B + 10

问题在于,当我执行以下更新语句时,B的值会正确更新,但C的值会根据B的旧值更新,这是null,而不是更新的:

Update Vars set B=A*A, C=B+10;

任何人都可以通过一种方式帮助我,使用单个更新语句,根据C的更新值计算B

提前谢谢。

2 个答案:

答案 0 :(得分:2)

使用一系列嵌套子查询以正确的顺序计算表达式。每个内部选择都会在外部列之前对列进行转换。

第一个子查询(内部)将在列列表中包含ROWID,最后一个(外部)将使用UPDATE ROWID绑定内部ROWID。每个中间子查询必须包括其计算,外部子查询所需的列以及第一个子查询生成的ROWID。

UPDATE VARS V
    SET (B,C) = 
        (SELECT B, B+10 AS C 
          FROM (SELECT A*A AS B, ROWID AS X FROM VARS) 
          WHERE V.ROWID = X
        );

不要担心嵌套子查询的性能。无论你有多少级别的子查询,oracle都只执行1次全表访问(更新)和1次基于rowid的访问(子查询)。完全访问是由于您的UPDATE中缺少WHERE。

我在11gR2上测试过它。 Oracle优化器令人印象深刻......真的很可怕。

答案 1 :(得分:0)

如果必须这样做,可以考虑的一个选项是更新内联视图。

如果您可以定义以下表单的查询:

select *,
       a * a new_b,
       (a * a) + 10 new_c
from   vars

...那么你也可以......

update (
  select *,
         a * a new_b,
         (a * a) + 10 new_c
  from   vars)
set b = new_b,
    c = new_c

这也使逻辑非常可测试,因为您可以将内联视图作为选项来运行,以测试将要设置的值。

你甚至可能有嵌套的内嵌视图......

select
  v.*,
  new_b + 10 new_c
from (
  select
    *,
    a * a new_b
  from
    vars) v