I need extract the data inserted into a table into two tables - sql

I need extract the data inserted into a table and extract the data inserted into last table and insert into another table table
create table tab1 (id bigint identity(1,1), col_1 varchar(4))
create table tab2 (id bigint identity(1,1), col_1 varchar(4), id_tab1 bigint)
create table tab3 (id bigint identity(1,1), col_1 varchar(4), id_tab2 bigint)
create table tab4 (id bigint identity(1,1), col_1 varchar(4), id_tab3 bigint)
insert into tab1 (col_1)
values ('AAAA'),('BBBB'),('CCCC')
insert into tab2 (col_1, id_tab1)
output inserted.col_1, inserted.id into tab3 (col_1, id_tab2)
--I NEED DO: OUTPUT FROM TAB3 INTO TAB4
output inserted.tab3.col_1, inserted.tab3.id into tab4 (col_1, id_tab3)
select col_1, id
from tab1

The output clause requires an explicit INSERT. So, use temporary tables:
declare #t2ids table (col_1 varchar(4), id_tab2 int);
insert into tab2 (col_1, id_tab1)
output inserted.col_1, inserted.id into #t2ids (col_1, id_tab2);
declare #t3ids (col1 varchar(4), id_tab3);
insert into tab3 (col1, id_tab2)
output inserted.col_1, inserted.id into #t3ids (col_1, id_tab3)
select col_1, id_tab2
from #t2ids;
insert into tab4 (col_1, id_tab3)
select col_1, id_tab3
from #t3ids;

You seem to be attempting to implement an "insert cascade" - meaning that an insert into the first table will automatically insert default values to the related table, and from that to the next related table and so on (up to tab4).
I would use triggers instead of the output clause for such a thing - create a trigger for insert on each table that will insert the relevant records to the next one:
create trigger trg_tab2_insert on tab2 for insert
as
insert into tab3(col_1, id_tab2)
select col_1, id
from inserted
and then
create trigger trg_tab3_insert on tab3 for insert
as
insert into tab4(col_1, id_tab3)
select col_1, id
from inserted
Please note that for this to work nested trigger should be enabled (Which is the default state in SQL Server)

Can you not run it as one script?
for instance script.sql:
insert into tab2 (col_1,id_tab1) select col_1,id from tab1
insert into tab3 (col_1,id_tab2) select col_1,id from tab2
insert into tab4 (col_1,id_tab3) select col_1,id from tab3

Related

Trigger to insert same table after condition is satsified

I want to insert a row if the field 'Rem' is yes. I am using triggers. Here the issue is I want to insert the data in the same table. Could you please let me know if you have come across this scenario?
Example:
create table Table1
(
id int,
name varchar(100),
is_rem varchar(20)
);
create or replace trigger Table1Trigger
after insert
on Table1
for each row
when (new.is_rem ='yes')
begin
insert into Table1 (id, name, is_rem)
values (:new.id, :new.name, :new.is_rem);
end; /
If I am inserting the is_rem as yes, the table should have two rows of the same data.
Below should works in MySQL
create table if not exists Table1 ( id int, name varchar(100), is_rem varchar(20) );
insert into Table1
select new_id as id, new_name as name, new_is_rem as is_rem
from Table2 where new_is_rem = 'yes';

Joining multiple table Sql trigger

Hi I am newbie to SQL trigger. since I tried and searched on online and I dont find any clear outcome.
so here is my problem.
I have three tables:
TABLE1 :
ID NAME (columns )
1 prabhu
TABLE2 :
Id COUNTRY (columns )
1 India
I want this to send to log table if anything like insert/update happen in table2
The SQL(DB2) trigger has to do the following and the result should be in log table like this
LOGTABLE:
ID NAME COUNTRY
1 prabhu India
Your help really appreciated.
Try this,
-- Create tables
create table table1(id int, empName varchar(20));
create table table2(id int, country varchar(20));
create table logtable(id int, empName varchar(20), country varchar(20));
-- Create trigger
CREATE TRIGGER logtableAfterInsert ON table2
after INSERT,DELETE,UPDATE
AS
BEGIN
declare #empid int;
declare #empname2 varchar(20);
declare #empcountry varchar(20);
select #empid=i.id from inserted i;
select #empcountry=i.country from inserted i;
select #empname2=tbl1.empName from table1 tbl1 where tbl1.id=#empid;
insert into logtable values(#empid,#empname2,#empcountry);
PRINT 'Inserted'
END
GO
After that insert the values,
insert into table1 values(1, 'prabhu');
insert into table2 values (1, 'India');
Check the results,
select * from table1;
select * from table2;
select * from logtable;
Hope this resolves...
BTW, You need to add the foreign key constraint.
CREATE OR REPLACE TRIGGER logtableAfterUpdate
AFTER UPDATE ON table2
REFERENCING NEW AS NAUDIT OLD AS OAUDIT
FOR EACH ROW MODE DB2SQL
--BEGIN --ATOMIC
insert into logtable
values(
(select id from table2 tbl2 where tbl2.id =OAUDIT.id),
(select empName from table1 tbl1 where tbl1.id=(select id from table2 tbl2 where tbl2.id =OAUDIT.id)),
(select country from table2 tbl2 where tbl2.id =OAUDIT.id)
);
--END;

How do I update a table based off the generated index key of an insert?

I'm created a temp table with most of the values I need to insert into a set of tables. From this temp table I have all the values I need for the insert to the first table, but the insert to the next table depends on the identity key generated by the insert to the first table.
I could very well just update my temp table after the first insert, but I'd like to try using the output clause.
I want something like this:
INSERT INTO Table1
<values from temp table>
OUTPUT <update my temp table with generated identity keys>
INSERT INTO Table2
<values from temp table including the output updated id column>
I think you better create another temp table (OR) table type variable and go from there as shown below. Cause I don't think you can update the same temp table from where you are inserting using output clause.
CREATE TABLE TestTable (ID INT not null identity primary key,
TEXTVal VARCHAR(100))
create TABLE #tmp(ID INT, TEXTVal VARCHAR(100))
create TABLE #tmp1(ID INT, TEXTVal VARCHAR(100))
CREATE TABLE TestTable1 (ID INT not null, TEXTVal VARCHAR(100))
INSERT #tmp (ID, TEXTVal)
VALUES (1,'FirstVal')
INSERT #tmp (ID, TEXTVal)
VALUES (2,'SecondVal')
INSERT INTO TestTable (TEXTVal)
OUTPUT Inserted.ID, Inserted.TEXTVal INTO #tmp1
select TEXTVal from #tmp
INSERT INTO TestTable1 (ID, TEXTVal)
select ID, TEXTVal from #tmp1
You could merge your temptable into Table1, and output the results to a variable table, then insert the original data joined to the variable table into Table2.
Example:
DECLARE #MyIDs TABLE (TempTableID int NOT NULL, Table1ID int NOT NULL)
MERGE INTO Table1
USING TempTable AS Tmp
ON Table1.SomeValue = Tmp.SomeValue
WHEN NOT MATCHED THEN
INSERT (col1, col2, col3, col4, col5)
VALUES (tmp.col1, tmp.col2, tmp.col3, tmp.col4, tmp.col5)
OUTPUT Tmp.ID
,Table1.ID
INTO #MyIDs;
INSERT INTO Table2 (col1, col2, col3, col4, col5, Table1ID)
SELECT tmp.col1, tmp.col2, tmp.col3, tmp.col4, tmp.col5, new.Table1ID
FROM TempTable tmp
JOIN #MyIDs new ON tmp.ID = new.TempTableID

Insert instead of from select and inserted data

I'm having trouble creating a trigger in a SQLite DB on a view that inserts values into 2 different tables and then inserts the "ID" values from those tables and values from the inserted data into a 3rd table. So basic idea is ....
CREATE TABLE [TBL1] (ID UNIQUE INT AUTOINCREMENT,VAL1);
CREATE TABLE [TBL2] (ID UNIQUE INT AUTOINCREMENT,VAL2);
CREATE TABLE [TBL3] (ID1 INT,ID2 INT,VAL3);
CREATE VIEW [v_TBL3] AS
SELECT (TBL1.VAL1,TBL2.VAL2,TBL3.VAL3)
FROM TBL3
INNER JOIN TBL1 ON TBL3.ID1 = TBL1.ID
INNER JOIN TBL2 ON TBL3.ID2 = TBL2.ID;
========== heres the problem ==========
CREATE TRIGGER [t_TBL3_INSERT] INSTEAD OF INSERT ON v_TBL3
BEGIN
INSERT OR IGNORE INTO [TBL1] (VAL1) VALUES NEW.VAL1;
INSERT OR IGNORE INTO [TBL2] (VAL2) VALUES NEW.VAL2;
INSERT INTO [TBL3] (ID1,ID2,v_TBL3.VAL3)
SELECT (TBL1.ID,TBL2.ID,VAL3)
FROM TBL1,TBL2,v_TBL3
WHERE TBL1.VAL1 = v_TBL3.VAL1 AND TBL2.VAL2 = v_TBL3.VAL2;
END;
I've looked on around on the net but I'm not finding quite what I need to get me there. Can someone help me get there?
You did not mention what your problem is, but when using proper SQL syntax, your schema would look like this:
CREATE TABLE TBL1 (ID INTEGER PRIMARY KEY AUTOINCREMENT, VAL1);
CREATE TABLE TBL2 (ID INTEGER PRIMARY KEY AUTOINCREMENT, VAL2);
CREATE TABLE TBL3 (ID1 INT, ID2 INT, VAL3);
CREATE VIEW v_TBL3 AS
SELECT TBL1.VAL1, TBL2.VAL2, TBL3.VAL3
FROM TBL3
INNER JOIN TBL1 ON TBL3.ID1 = TBL1.ID
INNER JOIN TBL2 ON TBL3.ID2 = TBL2.ID;
CREATE TRIGGER t_TBL3_INSERT
INSTEAD OF INSERT ON v_TBL3
BEGIN
INSERT OR IGNORE INTO TBL1 (VAL1) VALUES (NEW.VAL1);
INSERT OR IGNORE INTO TBL2 (VAL2) VALUES (NEW.VAL2);
INSERT INTO TBL3 (ID1, ID2, VAL3)
SELECT TBL1.ID, TBL2.ID, VAL3
FROM TBL1, TBL2, v_TBL3
WHERE TBL1.VAL1 = v_TBL3.VAL1 AND TBL2.VAL2 = v_TBL3.VAL2;
END;

Dependent insert statements

I have a table with data about a customer, Customer(name, address), with rows like "John Doe", "Some Street 123". For each row in the table, I want to insert one row in the Person(id, name) table and also one row in the Address(id, person_id, address) table.
I can accomplish this by running two insert statements for each row in Customer:
insert into Person(name) values (#name);
insert into Address(person_id, address) values (scope_identity(), #address);
But this is inefficient. I want to do the inserts in a batch, kind of like this:
-- This works, the problem is with the Address table...
insert into Person(name)
select name from Customer
-- This looks good but does not work because name is not unique.
insert into Address(person_id, address)
select p.person_id, c.address
from Customer c join Person p on c.name = p.name
Leaving this here for the fellow Google traveler that finds this post like me.
I found this solution, and it seems to work great, and doesn't require any funky schema alterations:
https://dba.stackexchange.com/questions/160210/splitting-data-into-two-tables-in-one-go
They use a MERGE statement to perform the initial insert into the first table (the table that is generating the identity to be used everywhere else). The reason it uses the MERGE statement is because it allows you to use an OUTPUT statement, which you can use to output both the new identity value as well as the identity value from the source table (as opposed to using an OUTPUT statement on a standard INSERT which does not allow you to output the source tables identity). You can insert this output data into a mapping table, and use that mapping table to perform the second insert.
Here's my sample code for the solution:
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Set up sample schema and data
------------------------------------------------------------------------------
--Source Data
IF OBJECT_ID('dbo.tmp1') IS NOT NULL DROP TABLE dbo.tmp1 --SELECT * FROM dbo.tmp1
CREATE TABLE dbo.tmp1 (tmp1ID INT IDENTITY(1,1), Col1 CHAR(1) NOT NULL, Col2 CHAR(1) NOT NULL, Col3 CHAR(1) NOT NULL, Col4 CHAR(1) NOT NULL, Col5 CHAR(1) NOT NULL, Col6 CHAR(1) NOT NULL)
INSERT INTO dbo.tmp1 (Col1, Col2, Col3, Col4, Col5, Col6)
SELECT x.c1, x.c2, x.c3, x.c4, x.c5, x.c6
FROM (VALUES ('A','B','C','D','E','F'),
('G','H','I','J','K','L'),
('M','N','O','P','Q','R')
) x(c1,c2,c3,c4,c5,c6)
IF OBJECT_ID('dbo.tmp3') IS NOT NULL DROP TABLE dbo.tmp3 --SELECT * FROM dbo.tmp3
IF OBJECT_ID('dbo.tmp2') IS NOT NULL DROP TABLE dbo.tmp2 --SELECT * FROM dbo.tmp2
--Taget tables to split into
CREATE TABLE dbo.tmp2 (
tmp2ID INT IDENTITY(1,1) NOT NULL CONSTRAINT PK_tmp2 PRIMARY KEY CLUSTERED (tmp2ID ASC)
, Col1 CHAR(1) NOT NULL
, Col2 CHAR(1) NOT NULL
, Col3 CHAR(1) NOT NULL
)
CREATE TABLE dbo.tmp3 (
tmp2ID INT NOT NULL
, Col4 CHAR(1) NOT NULL
, Col5 CHAR(1) NOT NULL
, Col6 CHAR(1) NOT NULL
, CONSTRAINT FK_tmp3_tmp2ID FOREIGN KEY(tmp2ID) REFERENCES dbo.tmp2 (tmp2ID)
)
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Split data into two tables
------------------------------------------------------------------------------
DECLARE #Mapping TABLE (tmp1ID INT NOT NULL, tmp2ID INT NOT NULL);
--Use merge statment to output the source data PK as well as the newly inserted identity to generate a mapping table
MERGE INTO dbo.tmp2 AS tgt
USING dbo.tmp1 AS src ON (1=0)
WHEN NOT MATCHED THEN
INSERT ( Col1, Col2, Col3)
VALUES (src.Col1, src.Col2, src.Col3)
OUTPUT src.tmp1ID, Inserted.tmp2ID INTO #Mapping (tmp1ID, tmp2ID);
--Use the mapping table to insert the split data into the second table
INSERT INTO dbo.tmp3 (tmp2ID, Col4, Col5, Col6)
SELECT t2.tmp2ID, t1.Col4, t1.Col5, t1.Col6
FROM dbo.tmp2 t2
JOIN #Mapping m ON m.tmp2ID = t2.tmp2ID
JOIN dbo.tmp1 t1 ON t1.tmp1ID = m.tmp1ID
SELECT tmp2ID, Col1, Col2, Col3 FROM dbo.tmp2
SELECT tmp2ID, Col4, Col5, Col6 FROM dbo.tmp3
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Clean up
------------------------------------------------------------------------------
DROP TABLE dbo.tmp1
DROP TABLE dbo.tmp3
DROP TABLE dbo.tmp2
------------------------------------------------------------------------------
------------------------------------------------------------------------------
GO
there is no way to do this as you explain because you lost scope_identity() value of each row of first insert.
A work around may be add Customer primary key fields to Person table and then make join of second insert with this fields:
before insert create customerID field on Person
alter table Person add customerID int null;
then bulk inserts:
-- inserting customerID
insert into Person(name, customerID)
select name, customerID from Customer
-- joining on customerID.
insert into Address(person_id, address)
select p.person_id, c.address
from Customer c
join Person p on c.customerID = p.customerID
after that you can remove customerID field from Person table:
alter table Person drop column customerID
It's better that you create some field of unique types in both table are related them.otherwise you want join as you dont have unique field for condition