views:

334

answers:

3

How would you update data in multiple tables using a single query?

MySQL Example

The equivalent code in MySQL:

UPDATE party p
LEFT JOIN party_name n ON p.party_id = n.party_id
LEFT JOIN party_details d ON p.party_id = d.party_id
LEFT JOIN incident_participant ip ON ip.party_id = p.party_id
LEFT JOIN incident i ON ip.incident_id = i.incident_id
SET
  p.employee_id = NULL,
  c.em_address = '[email protected]',
  c.ad_postal = 'x',
  n.first_name = 'x',
  n.last_name = 'x'
WHERE
  i.confidential_dt IS NOT NULL

What would be the same statement using Oracle 11g?

Thank you!

RTFM

It seems a single query is insufficient when using Oracle:

http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96540/statements_108a.htm#2067717

A: 

I was having the same problem I couldn't find a easy way to do this in Oracle.

Look here: Oracle Update Statements for more info.

Irfan Mulic
+1  A: 

You could use Oracle MERGE statement to do this. It is a bulk update-or-insert kind of statement based on joining the target table with an inline view.

MERGE INTO bonuses D
   USING (
      SELECT employee_id, salary, department_id FROM employees
      WHERE department_id = 80
   ) S ON (D.employee_id = S.employee_id)
 WHEN MATCHED THEN 
   UPDATE SET D.bonus = D.bonus + S.salary*.01
 WHEN NOT MATCHED THEN 
   INSERT (D.employee_id, D.bonus)
   VALUES (S.employee_id, S.salary*0.1);

if you do not need the insert part, you just omit the last 3 lines above.

Niels Wind
Although your question is about updating multiple tables at the same time - not an option with MERGE.
Nick Pierpoint
Oops - you're quite right - misread the question. Sorry
Niels Wind
+2  A: 
/** XXX CODING HORROR... */

Depending on your needs, you could use an updateable view. You create a view of your base tables and add an "instead of" trigger to this view and you update the view directly.

Some example tables:

create table party (
    party_id integer,
    employee_id integer
    );

create table party_name (
    party_id integer,
    first_name varchar2(120 char),
    last_name varchar2(120 char)
    );

insert into party values (1,1000);   
insert into party values (2,2000);
insert into party values (3,3000);

insert into party_name values (1,'Kipper','Family');
insert into party_name values (2,'Biff','Family');
insert into party_name values (3,'Chip','Family');

commit;

select * from party_v;

PARTY_ID    EMPLOYEE_ID    FIRST_NAME    LAST_NAME
1            1000           Kipper        Family
2            2000           Biff          Family
3            3000           Chip          Family

... then create an updateable view

create or replace view party_v
as
select
    p.party_id,
    p.employee_id,
    n.first_name,
    n.last_name
from
    party p left join party_name n on p.party_id = n.party_id;

create or replace trigger trg_party_update
instead of update on party_v 
for each row
declare
begin
--
    update party
    set
        party_id = :new.party_id,
        employee_id = :new.employee_id
    where
        party_id = :old.party_id;
--
    update party_name
    set
        party_id = :new.party_id,
        first_name = :new.first_name,
        last_name = :new.last_name
    where
        party_id = :old.party_id;
--
end;
/

You can now update the view directly...

update party_v
set
    employee_id = 42,
    last_name = 'Oxford'
where
    party_id = 1;

select * from party_v;

PARTY_ID    EMPLOYEE_ID    FIRST_NAME    LAST_NAME
1            42             Kipper        Oxford
2            2000           Biff          Family
3            3000           Chip          Family
Nick Pierpoint
Thanks for this, Nick. Sadly, it's a lot more work than just creating three different update statements all with the same where clause. That and harder to maintain (tables, views, and triggers vs. one procedure with three update statements). Until a better solution comes along, yours wins. ;-)
Dave Jarvis