How to insert autoincrementing id from one table into another in one command (using returning)? - sql

I've attempted the following:
INSERT INTO second_table(id, somethingelse)
VALUES(
(INSERT INTO first_table(post_text) VALUES('a text') RETURNING id),
'abcd123'
);
I know how to do select with 2 query, but I'm trying to avoid any concurrency issue by doing these 2 insertions at once. Above gives me the following error:
ERROR: syntax error at or near "INTO"
LINE 3: (INSERT INTO first_table(post_text) VALUES('a text...
I'm trying to insert auto-incrementing id from first_table into second_table when a row is inserted into first_table.

Use a data modifying CTE:
with first_insert as (
INSERT INTO first_table(post_text)
VALUES('a text')
RETURNING id
)
INSERT INTO second_table(id, somethingelse)
select id, 'abcd123'
from first_insert;

Try creating a trigger to be executed whenever a row is inserted in first table.
something like:
CREATE TRIGGER trigger_name AFTER INSERT OF post_text
ON first_table
[
INSERT INTO second_table(id, somethingelse)
VALUES(
(select id from first_table where post_text='a text'),
'abcd123'
);
];

You need to run below command to off identity column
Set Identity_Insert [TableName] Off

Related

Update table column with primary key after insert (in one statement)

Using an update statement, how can i directly set a column value to the primary key of an insert statement? I need this as one statement.
I know the following is wrong, but it helps get my idea through:
update AppNationalities
set CountrySelectionID = (
select [INSERTED.pkID] from
(
insert into CountrySelections
output INSERTED.pkID
values(CountryID, 'test', 0)
)
)
Put the values into a temporary table:
declare #ids table (pkID int);
insert into CountrySelections
output INSERTED.pkID into #ids
values (CountryID, 'test', 0);
update AppNationalities
set CountrySelectionID = i.id
from #ids i;
I don't think the output clause is allowed in the FROM clause of an UPDATE or DELETE statement.

ORACLE TRIGGER INSERT INTO ... (SELECT * ...)

Trigger with Insert into (select * ...)
I'm trying it.
INSERT INTO T_ USERS SELECT * FROM USERS WHERE ID = :new.ID;
not working...
this work.
INSERT INTO T_USERS(ID) VALUES(:new.ID);
Trigger
create or replace trigger "TRI_USER"
AFTER
insert on "USER"
for each row
begin
INSERT INTO T_USER SELECT * FROM USER WHERE ID = :new.ID;
end;​
this work.
INSERT INTO T_USERS(ID) VALUES(:new.ID);
So if it fits to you then try this:
INSERT INTO T_USER(ID) SELECT ID FROM USER WHERE ID = :new.ID;
If you want to select one or more rows from another table, you have to use this syntax:
insert into <table>(<col1>,<col2>,...,<coln>)
select <col1>,<col2>,...,<coln>
from ...;
Perhaps you could post the actual error you are experiencing?
Also, I suggest that you rethink your approach. Triggers that contain DML introduce all sorts of issues. Keep in mind that Oracle Database may need to restart a trigger, and could therefore execute your DML multiple times for a particular row.
Instead, put all your related DML statements together in a PL/SQL procedure and invoke that.
Its not about your trigger but because of INSERT statement
here insert statement works as below
INSERT INTO <TABLE>(COL1,COL2,COL3) VALUES (VAL1,VAL2,VAL3); --> If trying to populate value 1 by one.
INSERT INTO <TABLE>(COL1,COL2,COL3) --> If trying to insert mult vales at a time
SELECT VAL1,VAL2,VAL3 FROM <TABLE2>;
The number of values should match with number of columsn mentioned.
Hope this helps you to understand

Keyword 'Values' absent Oracle 9i

I'm trying to execute the following trigger when inserting some data in my table :
CREATE OR REPLACE TRIGGER AJOUTER_NEW_CONSISTANCE
AFTER INSERT OR UPDATE OF
CONSISTANCE_LIBELLE_1,CONSISTANCE_LIBELLE_2,CONSISTANC_LIBELLE_3
ON DB.ETAT_PARCELLAIRE
BEGIN
insert into DB.CONSISTANCE.LIBELLE
select consistance_libelle_1
from DB.ETAT_PARCELLAIRE
where DB.ETAT_PARCELLAIRE.consistance_libelle_1 not in (
select LIBELLE from DB.CONSISTANCE.LIBELLE);
END;
But it keeps giving me the following error :
PL/SQL : ORA00926 : Keyword Values absent.
How can I fix this ?
Thank you for help in advance :)
If CONSISTANCE is a table with a column called LIBELLE then you're referring to it incorrectly.
your insert is including the column, which I assume means the table has other columns and you only want to insert a value into that one, but your syntax is wrong (DB.CONSISTANCE.LIBELLE should be DB.CONSISTANCE(LIBELLE)). it is this line that's generating the ORA-00926.
your sub-select is including the column in the table name (DB.CONSISTANCE.LIBELLE should be just DB.CONSISTANCE)
So it should be:
CREATE OR REPLACE TRIGGER AJOUTER_NEW_CONSISTANCE
AFTER INSERT OR UPDATE OF
CONSISTANCE_LIBELLE_1,CONSISTANCE_LIBELLE_2,CONSISTANC_LIBELLE_3
ON DB.ETAT_PARCELLAIRE
BEGIN
insert into DB.CONSISTANCE(LIBELLE)
select consistance_libelle_1
from DB.ETAT_PARCELLAIRE
where consistance_libelle_1 not in (
select LIBELLE from DB.CONSISTANCE);
END;
I'm also not sure if CONSISTANC_LIBELLE_3 is a typo and it should be CONSISTANCE_LIBELLE_3.
You could also do a not exists instead of a not in:
insert into DB.CONSISTANCE(LIBELLE)
select CONSISTANCE_LIBELLE_1
from DB.ETAT_PARCELLAIRE
where not exists (
select 1
from DB.CONSISTANCE
where LIBELLE = DB.ETAT_PARCELLAIRE.CONSISTANCE_LIBELLE_1
);
Or use a merge:
merge into DB.CONSISTANCE c
using (select CONSISTANCE_LIBELLE_1 from DB.ETAT_PARCELLAIRE) ep
on (c.LIBELLE = ep.CONSISTANCE_LIBELLE_1)
when not matched then
insert (LIBELLE) values (ep.CONSISTANCE_LIBELLE_1);
Using a trigger to (partially) maintain that table looks odd though - it would be simpler to have a view which selects distinct values from ETAT_PARCELLAIRE:
create or replace view CONSISTANCE_VIEW as
select distinct CONSISTANCE_LIBELLE_1
from ETAT_PARCELLAIRE;
But they would have different content - once a value has appeared in CONSISTANCE_LIBELLE_1 it will always remain in CONSISTANCE as you are not removing defunct values, only inserting new ones; whereas CONSISTANCE_VIEW would only show values currently in the table. It isn't clear which behaviour you want.

I need insert 2 records in differents tables,

I need to insert 2 records into 2 different tables. The problem is that the two records will be with the same Id.
For example :
I have my Mannto table, with its IdMan and oters fields. I also have my Service table, with its IdServ.
What can I do to make this one equal? I am using Postgre. The Id of the Mannto table is serial and I need to use that one as a Foreign key in the Service table
I tried the following, but it does not work:
Insert into Mannto ( idMan, field 1 field2 ...etc)
values ( default, 'f1', 'f2'...etc)
Insert into Service ( idServ, fkMannto, field1...etc)
values (default, (in this part I need the same ManntoId called idMan), 'f1')
Thank you for any help you can provide!
INSERT INTO Mannto ( field1, field2 ...etc) VALUES ( 'f1', 'f2'...etc)
RETURNING idMan;
http://www.postgresql.org/docs/current/static/sql-insert.html
When field idMan uses a sequence to create a new value, you can refer to this value in the next INSERT using CURRVAL():
BEGIN; -- start transaction
INSERT INTO Mannto ( idMan, field 1 field2 ...etc)
VALUES ( default, 'f1', 'f2'...etc);
INSERT INTO Service ( idServ, fkMannto, field1...etc)
VALUES (default, currval('name_of_the_sequence') , 'f1');
COMMIT; -- commit both inserts
Maybe it's not the best solution but you could use a trigger.
CREATE TRIGGER MannToTrigger
AFTER INSERT OR UPDATE OR DELETE ON MannTo
FOR EACH ROW EXECUTE PROCEDURE insertService();
Fetch your MannTo inserted last code and throw the procedure after each insert.

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.
Maybe create a TRIGGER wich fires after inserting into a temp_table and updates the original
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;