【问题标题】:Updating two dependent columns using a single update statement in Oracle在 Oracle 中使用单个更新语句更新两个依赖列
【发布时间】:2015-06-23 05:30:56
【问题描述】:

我已经创建了这张表:

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;

谁能帮助我提供一种方法,允许使用单个更新语句根据B 的更新值计算C

提前谢谢你。

【问题讨论】:

  • 可以写"update vars set B = A * A, C = (A * A) + 10;
  • 其实列的真实计算太复杂了(我这里发的只是例子)。此外,我的表有 10 列,其中每一列都根据一组先前更新的列进行更新。
  • @TeeKea 你在使用 plsql 吗?这样最好把它写成 plsql 块
  • 要在 PL/SQL 中实现这一点,我需要多次执行更新语句(等于行数)。我的数据太大了,我需要更少的操作。
  • 您是否考虑过使用虚拟列而不是尝试维护物理列?

标签: sql oracle sql-update


【解决方案1】:

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

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

我已经在 11gR2 上测试过了。 Oracle 优化器令人印象深刻……真的很吓人。

【讨论】:

  • 嗯,我知道你在做什么,但是这可能会变得非常粗糙,需要根据彼此的值更新十列。
  • 是的!!!!它很丑……但很有效。 PL/SQL 会更漂亮,但效率较低(因为更新可以自动并行化,而 PL/SQL 块不能)......但这只会有点粗糙;-)。我已经测试了超过 10000 个子查询的非常粗糙的查询(1 个选择有 10000 个子选择),我的小 Oracle 实例可以毫无问题地解决它。
  • 感谢@acesargl,感谢您的有用回答,无论它应用于我的十列时多么复杂。
【解决方案2】:

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

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

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

【讨论】:

  • 抱歉,我无法执行这种查询:“select *, a from vars”。我收到此错误:“ORA-00923 FROM 关键字未在预期的位置找到”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-25
  • 2013-06-11
  • 1970-01-01
  • 2014-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多