更新单个列的所有行

时间:2009-07-28 08:12:03

标签: sql oracle oracle10g

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

表1:table_snapshot account_no | balance_due

表2:table_已付款 account_no | post_balance | 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;

感谢有人可以更正我的查询。

非常感谢。

新手。

3 个答案:

答案 0 :(得分:4)

试试这个

 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);

答案 1 :(得分:4)

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关系,则基于定义的键,您将收到此错误。这是甲骨文告诉你的方式,“你即将搞砸你的数据”。

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

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

答案 2 :(得分:1)

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