views:

470

answers:

3

Hi,

I'm dealing with two tables which have 2 columns, as listed under.

Table 1: table_snapshot account_no | balance_due

Table 2: table_ paid account_no | post_balance | delta_balance

I added a third column to table2 with the following command:

ALTER TABLE table_paid ADD delta_balance number(18);

I'm trying to use the following query, to update the new column ( delta_balance ) with the difference in balances between 1 and 2. FYI, table_paid is a subset of table_snapshot. i,e., table 2 has only a few accounts present in table 1. I get an error saying : SQL Statement not properly ended. the query i'm using is:

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;

Appreciate if someone can correct my query.

Many thanks.

novice.

+3  A: 

Try this

 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);
Babar
+1  A: 

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

palindrom
Hi babar and palindrom,Your query is going into a full table scan and is still in execution . table 1 has around 1.3 million records, and table 2 has 15k records.Any suggestions on how to increase the speed of scanning ?regards!
novice
For further reading see what Tom Kyte has to say about update on many rows - http://asktom.oracle.com/pls/asktom/f?p=100:11:0::NO::P11_QUESTION_ID:6407993912330
jva
create an index on table1(account_no) if u dont have already.
palindrom
+2  A: 

Oracle doesn't have the UPDATE ... FROM syntax that you're using from MS Sql Server (which, I believe, isn't ANSI anyway). Instead, when you need to do an update on a result set, Oracle has you create the resultset as a kind of inline view, then you update through the view, like so:

  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;

This is more "correct" than the answers supplied by Babar and palindrom, as their queries will update every row in table_paid, even if there are no corresponding rows in table_snapshot. If there is a 1-1 correspondance, you don't need to worry, but it's safer to do it with the inline view.

It's unclear from your example which table is the parent table, or (as I'm guessing) neither is the parent table and account_no is pointing to the primary key of another table (presumably account, or "table_account" by your naming conventions). In any case, it's clear that there is not a 1-1 correspondence in your table - 15K in one, millions in the other.

This could mean 2 things: either there are many rows in table_snapshot that have no corresponding row in table_paid, or there are many rows in table_snapshot for each row in table_paid. If the latter is true, your query is impossible - you will have multiple updates for each row in table_paid, and the result will be unpredictable; how will you know which of the "post_balance - balance_due" expressions will ultimately determine the value of a given delta_balance?

If you run my query, you will find this out quickly enough - you will get an error message that says, "ORA-01779: cannot modify a column which maps to a non key-preserved table". This error will appear based not on the data in the table (it may be okay), but based on the primary keys you have defined on the two tables. If the join condition you specify doesn't unambiguously result in a 1-1 relationship between the updated table and the rest of the join, based on the defined keys, you will get this error. It's Oracle's way of telling you, "You're about to screw up your data".

In the other answers here, you will only get an error (in that case, ORA-01427: single-row subquery returns more than one row) if you actually have data that would cause a problem; my version is more strict, so it may turn out that you will need to use the other versions.

And, as the others have said, you'll definitely want an index on account_no for the table_snapshot table. One on the table_paid wouldn't hurt either.

Steve Broberg
Excellent.. Thanks for the detailed info!
novice