Insert trigger with an IF statement - sql

I'm looking for a way to fire a trigger based on a condition and below is my sql. How do i include an IF statement in this trigger to fire if ac_mail = '1#mail.com'
CREATE TRIGGER username
ON temp
AFTER INSERT
AS
DECLARE #var1 int ,#var2 char (100)
select #var1 = al_id, #var2 = ac_mail
From temp
BEGIN
INSERT INTO user (v_id,v_m)
VALUES (#var1,#var2)
END
The trigger should only fire if ac_mail = '1#mail.com'

Triggers can fire for multiple rows - so using scalar variables to capture the data is usually wrong. As is querying the base table rather than inserted - inserted contains just the rows that caused the trigger to fire, whereas you're querying temp for any random row. And finally, of course, as I've said twice now, multiple rows. So you don't want an if because some of those rows might match your condition and other might not match.
I think you want:
CREATE TRIGGER username
ON temp
AFTER INSERT
AS
INSERT INTO user (v_id,v_m)
select al_id,ac_mail from inserted where ac_mail = '1#mail.com'
See how much simpler it is?

try this :-
CREATE TRIGGER username
ON temp
AFTER INSERT
AS
DECLARE #var1 int ,#var2 char (100)
Select #var1 = al_id
,#var2 = ac_mail
From inserted
IF #var2 = '1#mail.com'
BEGIN
INSERT INTO user (v_id,v_m)
VALUES (#var1,#var2)
END

Try this sql
CREATE TRIGGER username
After INSERT ON temp
REFERENCING NEW ROW AS New
FOR EACH ROW
if(New.ac_mail=='1#mail.com')
begin
INSERT INTO user (v_id,v_m)
VALUES (New.al_id,New.ac_mail)
end

Related

Create a string from inserted.id via trigger

I'm creating a trigger on insert that will create a new record in another table using the id from the newly inserted row.
I need to format the id before I insert it into the other table. This is my code so far.... having problems creating the formated #PseudoID.
CREATE TRIGGER OnInsertCreateUnallocatedPseudo
ON tblTeams
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
DECLARE #PseudoID NVARCHAR(50), #tmID NVARCHAR(10)
SELECT #tmID = CONVERT(nvarchar(10),inserted.tmID) FROM inserted
--NEED SOME CODE TO CREATE A PADDED OUT PseudoID e.g.
-- if #tmID = '7' then #PseudoID = 'PSU0007'
-- if #tnID = '25' then #PseudoID = 'PSU0025'
INSERT INTO [dbo].[tblUsersPseudo].....
END
You can't assign it to a variable within the trigger since there could be multiple rows, but you could do something like this to insert into the other table.
LEFT('PSU0000',LEN('PSU0000')-LEN(CONVERT(nvarchar(10),inserted.tmID))) + CONVERT(nvarchar(10),inserted.tmID)
You can't assume that Inserted has only a single row, you have to treat it as a table with 0-N rows and carry out set-based operations on it (rather than procedural).
FORMAT will format your existing id into the new format you require.
INSERT INTO [dbo].[tblUsersPseudo] (id, col1, col2, ...)
SELECT FORMAT(id,'PSU0000')
, col1, col2
FROM Inserted;

How to get a inserted id in other table from inside a trigger?

I have 3 tables tbl_Users, tbl_Protocol and tbl_ProtocolDetails and inside of my trigger on Users, I have to inserted into Protocol and then insert into ProtocolDetails, but I don't know how work the inserted scope.
Something like that:
CREATE TRIGGER tg_Users ON tbl_Users
AFTER INSERT, UPDATE AS
BEGIN
DECLARE #UserId = Int
DECLARE #ProtocolId = Int
DECLARE #UserDetail = NVARCHAR(255)
SELECT
#UserId = user_id,
#UserDetail = user_detail + '#' + user_explanation
FROM INSERTED
INSERT INTO tbl_Protocol (user_id, inserted_date)
VALUES (#UserId, GetDate())
-- Return Inserted Id from tbl_Protocol into #ProtocolDetail then
INSERT INTO tbl_ProtocolDetails (protocol_id, protocol_details)
VALUES (#ProtocolId, #UserDetail)
END
Your trigger has a MAJOR flaw in that you seems to expect to always have just a single row in the Inserted table - that is not the case, since the trigger will be called once per statement (not once for each row), so if you insert 20 rows at once, the trigger is called only once, and the Inserted pseudo table contains 20 rows.
Therefore, code like this:
Select #UserId = user_id,
#UserDetail = user_detail + '#' + user_explanation
From INSERTED;
will fail, since you'll retrieve only one (arbitrary) row from the Inserted table, and you'll ignore all other rows that might be in Inserted.
You need to take that into account when programming your trigger! You have to do this in a proper, set-based fashion - not row-by-agonizing-row stlye!
Try this code:
CREATE TRIGGER tg_Users ON tbl_Users
AFTER INSERT, UPDATE AS
BEGIN
-- declare an internal table variable to hold the inserted "ProtocolId" values
DECLARE #IdTable TABLE (UserId INT, ProtocolId INT);
-- insert into the "tbl_Protocol" table from the "Inserted" pseudo table
-- keep track of the inserted new ID values in the #IdTable
INSERT INTO tbl_Protocol (user_id, inserted_date)
OUTPUT Inserted.user_id, Inserted.ProtocolId INTO #IdTable(UserId, ProtocolId)
SELECT user_id, SYSDATETIME()
FROM Inserted;
-- insert into the "tbl_ProtocolDetails" table from both the #IdTable,
-- as well as the "Inserted" pseudo table, to get all the necessary values
INSERT INTO tbl_ProtocolDetails (protocol_id, protocol_details)
SELECT
t.ProtocolId,
i.user_detail + '#' + i.user_explanation
FROM
#IdTable t
INNER JOIN
Inserted i ON i.user_id = t.UserId
END
There is nothing in this trigger that would handle a multiple insert/update statement. You will need to either use one scenario that will handle multiple records or check how many records were effected with a IF ##ROWCOUNT = 1 else statement. In your example, I would just use something like
insert into tbl_Protocol(user_id, inserted_date)
select user_id, user_detail + '#' + user_explanation
From INSERTED;
As for your detail table, I see Marc corrected his answer to include the multiple lines and has a simple solution or you can create a second trigger on the tbl_Protocol. Another solution I have used in the past is a temp table for processing when I have very complicated triggers.

Insert trigger in SQL Server

I am trying to write a trigger that inserts in a log table the date, name of the table I inserted in, the name of the operation (insert, delete, update) and the number of insertion.
Here is my code:
CREATE TRIGGER [dbo].[Inser]
ON [dbo].[Avion]
AFTER INSERT
AS
BEGIN
DECLARE #codAv int
DECLARE #NumeAv varchar(100)
DECLARE #MotorAv varchar(100)
SELECT #codAv = INSERTED.codA FROM INSERTED
SELECT #NumeAv = INSERTED.NumeA FROM INSERTED
SELECT #MotorAv = INSERTED.Motor FROM INSERTED
SELECT ##ROWCOUNT AS INSERTED;
INSERT INTO LogM (DataM, Numele, Tipul, Numar)
VALUES(GETDATE(), 'Avion', 'Inserare', ##ROWCOUNT);
PRINT 'INSERT trigger fired.'
END
I have a stored procedure where I have something like 20 insertion of this type:
INSERT INTO Avion (Motor,NumeA)
VALUES ('Junkers','Focke-Wulf');
all separated from one another. When I run that code, the table LogM will be populated with 20 new rows of this type:
5 Nov 27 2016 8:58PM Avion Inserare 1.00
I want to make my trigger to count all the insertion stored in a procedure, then insert in LogM only one entry, with the ROWCOUNT not being 1.00, but the number of insertion I made in that stored procedure, and I don't have any idea how can I do this.
Thank you.
Instead of passing ##ROWCOUNT you can not just pass the ID?
##ROWCOUNT works to return the number of rows affected, as you enter one at a time, it will always be one.
CREATE TRIGGER [dbo].[Inser]
ON [dbo].[Avion]
AFTER INSERT
AS
BEGIN
DECLARE #codAv int
DECLARE #NumeAv varchar(100)
DECLARE #MotorAv varchar(100)
SELECT #codAv=INSERTED.codA FROM INSERTED
SELECT #NumeAv=INSERTED.NumeA FROM INSERTED
SELECT #MotorAv=INSERTED.Motor FROM INSERTED
INSERT INTO LogM
(DataM,Numele,Tipul,Numar)
VALUES(GETDATE(),'Avion','Inserare',#codAv);
PRINT 'INSERT trigger fired.'
END

How use inserted\deleted table in stored procedure?

I creating triggers for several tables. The triggers have same logic. I will want to use a common stored procedure.
But I don't know how work with inserted and deleted table.
example:
SET #FiledId = (SELECT FiledId FROM inserted)
begin tran
update table with (serializable) set DateVersion = GETDATE()
where FiledId = #FiledId
if ##rowcount = 0
begin
insert table (FiledId) values (#FiledId)
end
commit tran
You can use a table valued parameter to store the inserted / deleted values from triggers, and pass it across to the proc. e.g., if all you need in your proc is the UNIQUE FileID's:
CREATE TYPE FileIds AS TABLE
(
FileId INT
);
-- Create the proc to use the type as a TVP
CREATE PROC commonProc(#FileIds AS FileIds READONLY)
AS
BEGIN
UPDATE at
SET at.DateVersion = CURRENT_TIMESTAMP
FROM ATable at
JOIN #FileIds fi
ON at.FileID = fi.FileID;
END
And then pass the inserted / deleted ids from the trigger, e.g.:
CREATE TRIGGER MyTrigger ON SomeTable FOR INSERT
AS
BEGIN
DECLARE #FileIds FileIDs;
INSERT INTO #FileIds(FileID)
SELECT DISTINCT FileID FROM INSERTED;
EXEC commonProc #FileIds;
END;
You can
select * into #Inserted from inserted
select * into #Deleted from deleted
and then
use these two temp tables in your stored proc
The tables inserted and deleted are only available inside the trigger. You can only use them in run-time. They will then contain the affected rows.
Also, your code might not work as expected if there is not exactly one row inserted.

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!