在 Oracle 中使用单个更新语句更新两个相关列

Updating two dependent columns using a single update statement in Oracle

我创建了这个 table:

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的值是根据[=14=的旧值更新的],这是空的,不是更新的:

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

任何人都可以帮助我使用单个更新语句根据 B 的更新值计算 C 的方法。

提前谢谢你。

使用一系列嵌套子查询以正确的顺序评估表达式。每个内部 select 在外部列之前转换列。

第一个子查询(内部)将在列列表中包含 ROWID,最后一个(外部)将内部 ROWID 与 UPDATE 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 次完全 table 访问(更新)和 1 次基于 rowid 的访问(子查询)。完全访问权限是由于您的 UPDATE 中缺少 WHERE。

我已经在 11gR2 上测试过了。 Oracle optimizer 厉害了。。。真是吓人。

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

如果您可以定义如下形式的查询:

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 来测试将要设置的值。

您甚至可以嵌套内联视图...

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