简体   繁体   中英

Insert into a temporary table and update another table in one SQL query (Oracle)

Here's what I'm trying to do:

1) Insert into a temp table some values from an original table

INSERT INTO temp_table SELECT id FROM original WHERE status='t'

2) Update the original table

UPDATE original SET valid='t' WHERE status='t'

3) Select based on a join between the two tables

SELECT * FROM original WHERE temp_table.id = original.id

Is there a way to combine steps 1 and 2?

You can combine the steps by doing the update in PL/SQL and using the RETURNING clause to get the updated ids into a PL/SQL table.

EDIT:

If you still need to do the final query, you can still use this method to insert into the temp_table; although depending on what that last query is for, there may be other ways of achieving what you want. To illustrate:

DECLARE
  id_table_t IS TABLE OF original.id%TYPE INDEX BY PLS_INTEGER;
  id_table id_table_t;
BEGIN
  UPDATE original SET valid='t' WHERE status='t'
  RETURNING id INTO id_table;
  FORALL i IN 1..id_table.COUNT
    INSERT INTO temp_table
    VALUES (id_table(i));
END;
/

SELECT * FROM original WHERE temp_table.id = original.id;

No, DML statements can not be mixed.

There's a MERGE statement, but it's only for operations on a single table .

也许在插入temp_table之后创建触发触发的TRIGGER并更新原始

Create a cursor holding the values from insert and then loop through the cursor updating the table. No need to create temp table in the first place.

You can combine steps 1 and 2 using a MERGE statement and DML error logging. Select twice as many rows, update half of them, and force the other half to fail and then be inserted into an error log that you can use as your temporary table.

The solution below assumes that you have a primary key constraint on ID, but there are other ways you could force a failure.

Although I think this is pretty cool, I would recommend you not use it. It looks very weird, has some strange issues (the inserts into TEMP_TABLE are auto-committed), and is probably very slow.

--Create ORIGINAL table for testing.
--Primary key will be intentionally violated later.
create table original (id number, status varchar2(10), valid varchar2(10)
    ,primary key (id));

--Create TEMP_TABLE as error log.  There will be some extra columns generated.
begin
  dbms_errlog.create_error_log(dml_table_name => 'ORIGINAL'
    ,err_log_table_name => 'TEMP_TABLE');
end;
/

--Test data
insert into original values(1, 't', null);
insert into original values(2, 't', null);
insert into original values(3, 's', null);
commit;


--Update rows in ORIGINAL and also insert those updated rows to TEMP_TABLE.
merge into original original1
using 
(
  --Duplicate the rows.  Only choose rows with the relevant status.
  select id, status, valid, rownumber
  from original
    cross join
    (select 1 rownumber from dual union all select 2 rownumber from dual)
  where status = 't'
) original2
  on (original1.id = original2.id and original2.rownumber = 1)
--Only math half the rows, those with rownumber = 1.
when matched then update set valid = 't'
--The other half will be inserted.  Inserting ID causes a PK error and will
--insert the data into the error table, TEMP_TABLE.
when not matched then insert(original1.id, original1.status, original1.valid)
  values(original2.id, original2.status, original2.valid)
log errors into temp_table reject limit 999999999;


--Expected: ORIGINAL rows 1 and 2 have VALID = 't'.
--TEMP_TABLE has the two original values for ID 1 and 2.
select * from original;
select * from temp_table;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM