【问题标题】:Update all rows of a single column更新单个列的所有行
【发布时间】:2009-07-28 08:12:02
【问题描述】:

我正在处理两个有 2 列的表,如下所列。

表 1:table_snapshot 帐户号 | balance_due

表 2:table_paid 帐户号 |后余额 | delta_balance

我使用以下命令向 table2 添加了第三列:

ALTER TABLE table_paid ADD delta_balance number(18);

我正在尝试使用以下查询,使用 1 和 2 之间的余额差来更新新列 (delta_balance)。 仅供参考,table_paid 是 table_snapshot 的子集。即,表 2 在表 1 中只有几个帐户。我收到一条错误消息:SQL 语句未正确结束。我正在使用的查询是:

UPDATE table_paid
SET table_paid.delta_balance = table_paid.post_balance - table_snapshot.balance_due
from table_paid, table_snapshot
WHERE table_paid.account_no = table_snapshot.account_no;

如果有人可以更正我的查询,不胜感激。

非常感谢。

新手。

【问题讨论】:

    标签: sql oracle oracle10g


    【解决方案1】:

    Oracle 没有您在 MS Sql Server 中使用的 UPDATE ... FROM 语法(我相信,无论如何,这不是 ANSI)。相反,当您需要对结果集进行更新时,Oracle 会让您将结果集创建为一种内联视图,然后您通过视图进行更新,如下所示:

      UPDATE ( SELECT tp.delta_balance
                    , tp.post_balance
                    , ts.balance_due
                 FROM table_paid tp
                      JOIN table_snapshot ts
                        ON tp.account_no = ts.account_no
             )
         SET delta_balance = post_balance - balance_due;
    

    这比 Babar 和 palindrom 提供的答案更“正确”,因为他们的查询将更新 table_paid 中的每一行,即使 table_snapshot 中没有相应的行。如果有 1-1 的对应关系,您不必担心,但使用内联视图会更安全。

    从您的示例中不清楚哪个表是父表,或者(正如我猜测的那样)父表也不是父表,并且 account_no 指向另一个表的主键(大概是帐户,或您命名的“table_account”公约)。无论如何,很明显,您的表中没有 1-1 的对应关系——一个是 15K,另一个是数百万。

    这可能意味着两件事:table_snapshot 中有很多行在 table_paid 中没有对应的行,或者 table_snapshot 中有很多行对应于 table_paid 中的每一行。如果后者为真,则您的查询是不可能的——您将对 table_paid 中的每一行进行多次更新,结果将是不可预测的;您如何知道“post_balance - balance_due”表达式中的哪一个最终会确定给定 delta_balance 的值?

    如果您运行我的查询,您会很快发现这一点 - 您会收到一条错误消息,上面写着“ORA-01779:无法修改映射到非键保留表的列”。这个错误将不是基于表中的数据出现(可能没问题),而是基于你在两个表上定义的主键。如果您指定的连接条件没有明确地导致更新的表和连接的其余部分之间存在 1-1 关系,则基于定义的键,您将收到此错误。这是 Oracle 告诉您的方式,“您即将搞砸您的数据”。

    在这里的其他答案中,如果您确实有会导致问题的数据,您只会收到错误(在这种情况下,ORA-01427:单行子查询返回多行);我的版本更严格,因此您可能需要使用其他版本。

    而且,正如其他人所说,您肯定需要 table_snapshot 表的 account_no 索引。 table_paid 上的一个也不会受伤。

    【讨论】:

    • 优秀.. 感谢您提供详细信息!
    【解决方案2】:

    试试这个

     UPDATE table_paid
     SET table_paid.delta_balance = table_paid.post_balance - 
     (SELECT table_snapshot.balance_due from table_snapshot WHERE table_paid.account_no = 
     table_snapshot.account_no);
    

    【讨论】:

      【解决方案3】:

      更新 table_paid SET table_paid.delta_balance = table_paid.post_balance - ( 从 table_snapshot 中选择 balance_due WHERE table_paid.account_no = table_snapshot.account_no)

      【讨论】:

      • 嗨 babar 和 palindrom,您的查询正在进行全表扫描,并且仍在执行中。表 1 有大约 130 万条记录,表 2 有 15k 条记录。关于如何提高扫描速度的任何建议?问候!
      • 如需进一步阅读,请查看 Tom Kyte 对多行更新的看法 - asktom.oracle.com/pls/asktom/…
      • 如果您还没有,请在 table1(account_no) 上创建索引。
      猜你喜欢
      • 1970-01-01
      • 2015-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-26
      • 2014-01-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多