在 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);
现在,我想创建一个更新语句来修改 B
和 C
列的值,如下所示:
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
我创建了这个 table:
Create table Vars(A number, B number, C number);
然后,我插入了一个新行,其中只有第一列(即 A
)有一个值:
Insert Into Vars(A) values (2);
现在,我想创建一个更新语句来修改 B
和 C
列的值,如下所示:
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