How to Use FIRE_TRIGGERS in insert sql statement - sql

I am trying to copy data from table "tb_A" to itself (with different primary key).
When "tb_A" table is insert new record, I have written a trigger to populate another table "tb_B" with one record.
I ran the following statement.
INSERT INTO [tb_A]
([NAME])
select top (20)[NAME] from [tb_A]
I was expected 20 new records in "tb_B". But I didn't.
Anyway I saw FIRE_TRIGGERS is using during bulk insert to overcome this issue.
is there is a any way to use it on inset statements too ? Please provide me example.
Gayan
Trigger code (copied from Gayan's comment to gbn's answer):
CREATE TRIGGER UpdatetbB ON [dbo].[tb_A] FOR INSERT
AS
DECLARE #AID as int
SELECT #AID = [ID] FROM inserted
INSERT INTO [tb_B]([IDA]) VALUES (#AID)

The reason your trigger did not work properly is because it is poorly designed. Triggers fire once for each insert even if you are inserting a million records. You havea trigger that makes the assumption it will owrk one record at a time. Anytime you set a value form inserted or deleted to a scalar variable the trigger is wrong and needs to be rewritten. Try something like this instead.
CREATE TRIGGER UpdatetbB ON [dbo].[tb_A] FOR INSERT
AS
INSERT INTO [tb_B]([IDA])
SELECT [ID] FROM inserted

FIRE_TRIGGERS is only for BULK INSERT (and bcp), not "standard" INSERT
I'd expect your trigger to look something like
CREATE TRIGGER TRG_tbA_I ON tb_A FOR INSERT
AS
SET NOCOUNT ON
INSERT tb_B (col1, col2, ...)
SELECT col1, col2, ... FROM INSERTED
GO
You use the special INSERTED table to get the list of new rows in tb_A, then INSERT from this into tb_B. This works for more than one row
If you add the trigger code then we can explain what went wrong.
Edit: your trigger will only read a single row (any row, no particular order) from INSERTED. It isn't set based like my rough example.

Related

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

SQL trigger to add new records to a table with the same structure when an insertion is made

I am trying to create SQL trigger which adds a new record to the same table where an insertion is made through a web page. I am not exactly sure how to implement it but I tried the following query
CREATE trigger [dbo].[trgI_DealsDoneInserRecord]
on [dbo].[Terms]
after insert
As
Insert into DealsDone
(Company,Grade,Term,Pipeline,[Index],Volume,Price,[Type],CounterParty,
TermID,GradeID,CPID,Locked,Product)
VALUES
(SELECT Company,Grade,Term,Pipeline,[Index],Volume,Price,[Type],CounterParty,
TermID,GradeID,CPID,Locked,Product FROM inserted)
END
The above query threw an error in the SELECT statement in VALUES.
May I know a way to implement this?
Try this:
CREATE trigger [dbo].[trgI_DealsDoneInserRecord]
ON [dbo].[Terms]
AFTER INSERT
As
BEGIN
INSERT INTO DealsDone
(Company,Grade,Term,Pipeline,[Index],Volume,Price,[Type],CounterParty,
TermID,GradeID,CPID,Locked,Product)
SELECT Company,Grade,Term,Pipeline,[Index],Volume,Price,[Type],CounterParty,
TermID,GradeID,CPID,Locked,Product FROM inserted
END
While I generally advocate against using SELECT *, in this case it seems like a benefit:
By not specifying the fields you can automatically account for changes in the tables without having to update this trigger if you add or remove or even rename fields.
This will help you catch errors in schema updates if one of the tables is updated but the other one isn't and the structure is then different. If that happens, the INSERT operation will fail and you don't have to worry about cleaning up bad data.
So use this:
CREATE TRIGGER [dbo].[trgI_DealsDoneInserRecord]
ON [dbo].[Terms]
AFTER INSERT
AS
SET NOCOUNT ON;
INSERT INTO [DealsDone]
SELECT *
FROM inserted;
There is an syntax issue, and also you are missing BEGIN
The basic syntax is
INSERT INTO table2 (column_name(s))
SELECT column_name(s)
FROM table1;
So try this
CREATE trigger [dbo].[trgI_DealsDoneInserRecord]
on [dbo].[Terms]
after insert
As
BEGIN
Insert into DealsDone
(Company,Grade,Term,Pipeline,[Index],Volume,Price,[Type],CounterParty,
TermID,GradeID,CPID,Locked,Product)
SELECT Company,Grade,Term,Pipeline,[Index],Volume,Price,[Type],CounterParty,
TermID,GradeID,CPID,Locked,Product
FROM inserted
END
Refer:- http://technet.microsoft.com/en-us/library/ms188263(v=sql.105).aspx

Can SQL server instead of update force insert a new row

Is it possible in SQL Server 2008+ to force an UPDATE statement on table to be transformed into INSERT statement, thus creating new row with the old and updated columns?
Yes this is a typical scenario for an INSTEAD OF UPDATE TRIGGER.
Create the following trigger on your table and it will insert a row for each update made on your table. you can have a bit more logic inside your trigger but this is just a basic definition just to give you some idea.
Inside your INSTEAD of UPDATE trigger you will have access to two system tables Inserted and deleted.
Inserted table will hold new values for the row that was being updated by the Update statement.
Deleted table will hold Old values for the row that was being updated by the Update statement.
Demo Trigger
CREATE TRIGGER tr_Table_Instead_Of_Update
ON TABLE_NAME
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO TABLE_NAME(Col1, Col2 , Col3)
SELECT Col1, Col2 , Col3
FROM inserted
END

Issue with SQL Server trigger event firing

I have a trigger on a table that is something like this:
ALTER TRIGGER [shoot_sms]
ON [dbo].[MyTable]
AFTER INSERT
AS
begin
declare #number bigint
declare #body varchar(50)
declare #flag int
select #number=number,#body=body,#flag=flag from inserted
if(#flag=0)
begin
insert into temptable (number,body,status)
select #number,#body,'P'
end
end
Now I am making two entries in mytable as below:
insert into mytable(number, body, flag)
values(3018440225, 'This is test', 0)
insert into mytable(number, body, flag)
values(3018440225, 'This is test', 0)
I execute these queries at a time, but for both of the queries the trigger fires only once and performs the task for the first query only.
How can I make it work for both insert statements?
Just an idea but put a GO statement between those two insert statements and that might cause the trigger to fire twice.
You should probably rewrite your trigger to handle multiple row inserts I think.
Here is your query converted. You should get two rows now.
ALTER TRIGGER [shoot_sms]
ON [dbo].[MyTable]
AFTER INSERT
AS
begin
insert into temptable (number,body,status)
select number,body,'P'
from inserted
where flag = 0
end
Also notice your trigger is much simpler now.
Since those two statements are in one SQL batch, the trigger will (by design) only fire once.
Triggers don't fire once per row - they fire once per statement! So if you have an INSERT or UPDATE statement that affects more than one row, your trigger will have more than one row in the Inserted (and possibly Deleted) pseudo tables.
The way you wrote this trigger is really not taking into account that Inserted could contain multiple rows - what row do you select from the Inserted table if you're inserting 20 rows at once?
select #number = number, #body = body, #flag = flag from inserted
You need to change your trigger to take that into account!

SQL Server 2005 triggers

I created a trigger on a table for updates. If any update happens, I want to store the old value in separate table. I am trying to get the old value from "inserted" table, but this table is not populated with old values after update.
Here is the sample code:
CREATE TRIGGER [dbo].[Logs_Update]
ON [dbo].[Logs] AFTER UPDATE
AS
DECLARE #url varchar(50)
BEGIN
SELECT #url = i.url
FROM INSERTED i
INSERT INTO dbo.Triggers_tbl
(ID, URL)
VALUES
(1000, #url)
END
I get #url as null from the inserted table.
Please let me know what is wrong with the trigger
The DELETED table contains the "old" values and the "INSERTED" table contains the "new" values.
To add to this, the INSERTED and DELETED tables may contain multiple rows if your update affects multiple rows and therefore you should probably run your insert with an INSERT SELECT rather than a variable.
INSERT INTO dbo.Triggers_tbl(URL) SELECT d.url FROM DELETED d
The "old" values (after an UPDATE) are available in the Deleted pseudo-table:
CREATE TRIGGER [dbo].[Logs_Update]
ON [dbo].[Logs]
AFTER UPDATE
AS
DECLARE #url varchar(50)
SELECT #url = d.url from deleted d
INSERT INTO dbo.Triggers_tbl(ID,URL) VALUES(1000,#url)
As HLGEM correctly commented on, the OP's code is assuming the trigger will be called for each row separately - which is not correct.
In that light, the trigger code really ought to deal with a set of rows being updated, and thus it should be something like:
CREATE TRIGGER [dbo].[Logs_Update]
ON [dbo].[Logs]
AFTER UPDATE
AS
INSERT INTO dbo.Triggers_tbl(ID,URL)
SELECT 1000, d.url
FROM Deleted d
or something like that.
The records that were updated are in the DELETED virtual table, not INSERTED. Change "from inserted" to "from deleted" and that should work.