简体   繁体   中英

Insert data in table, update other table with FK in one query

I have one Table A with 3 attributes:

ID (PK), UNIT(varchar2), VALUE(number)

And I have another Table B that references the PK of Table A via a foreign key.

ID, FK_TABLE_A

In Table B are already records, but the value of the attribute FK_TABLE_A is null. What I want is, that all records in Table B get an own unique reference to Table A's PK by inserting new data into Table A and referencing the newly created primary key as foreign key into Table B.

What I have done so far: I can now insert new data via following SQL:

INSERT INTO TABLE_A(ID, UNIT, VALUE) VALUES (TABKE_A_SEQ.nextval, 'SOME_STRING', 1);

And I can update by hand the refernce to Table B

UPDATE TABLE_B SET FK_TABLE_A = 123; //123 is just an example PK

But I do not want to query for each record everytime the DB, but instead want to combine somehow the first insert with the second update in one query. So that the update takes the newly created PK in Table A as reference.

Is this possible?

I am using Oracle as DB.

Once you've used the sequence in your session, you can use the currval pseudocolumn to get the last sequence value issued in your session, by the last nextval call:

INSERT INTO TABLE_A(ID, UNIT, VALUE) VALUES (TABKE_A_SEQ.nextval, 'SOME_STRING', 1);
UPDATE TABLE_B SET FK_TABLE_A = TABKE_A_SEQ.currval;

(Although as you don't have a filter, that will update all rows in table B to the same FK value; presumably you're doing something more complicated to identify the relevant rows...)


If you want a one-to-one relationship and don't care which row gets which PK value, and you can make the constraint deferrable, you could approach it the other way around; update all the table B rows using the sequence, then create the table A rows using those.

With a quick demo table:

create table table_a (id number primary key, unit varchar2(20), value number);
create table table_b (id number,
  fk_table_a number references table_a(id) initially deferred deferrable);
create sequence table_a_seq;
create sequence table_b_seq start with 50;

insert into table_b (id) select table_b_seq.nextval from dual connect by level <= 5;

Then, in a single transaction, update all the rows and do a single insert:

update table_b set fk_table_a = table_a_seq.nextval;

insert into table_a (id, unit, value)
select fk_table_a, 'SOME_STRING', 1
from table_b;

The constraint has to be deferrable to allow the update to happen first; otherwise you'd get ORA-02291.

If the unit/value are coming from table_a you can include those in the query instead of using fixed literals. It's hard to tell what you actually need for those, and you said they could even be left null.

Now you have:

select * from table_a;

        ID UNIT                      VALUE
---------- -------------------- ----------
         1 SOME_STRING                   1
         2 SOME_STRING                   1
         3 SOME_STRING                   1
         4 SOME_STRING                   1
         5 SOME_STRING                   1

select * from table_b;

        ID FK_TABLE_A
---------- ----------
        50          1
        51          2
        52          3
        53          4
        54          5

Use a trigger (on TABLE_A) to create the row in TABLE_B.

For example (assuming you are using a SEQUENCE to generate the PK)

 CREATE OR REPLACE TRIGGER TR_TABLE_A_AI
 AFTER INSERT
 ON TABLE_A
 FOR EACH ROW
BEGIN
  INSERT INTO TABLE_B VALUES (SEQ_TABLE_B.NEXTVAL, :NEW.ID);
END;

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