ERROR in TRIGGER AFTER INSERT - sql

I have a problem with the next TRIGGER in SQL server 2008:
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Order int,
#Payment varchar(15)
select #order=OrderID,#payment=PaymentType from inserted
IF #Payment='paypal'
begin
exec PaypalTransactionsUpdate #OrderID=#Order
end
ELSE
begin
Return
end
END
I can't understand why does not work the select from the inserted table. If I use like:
select TOP 1 #order=OrderID,#payment=PaymentType from TABLENAME where PaymentType='Paypal' order by OrderID desc.
It works perfectly, anybody can help me? I want to use the row table inserted to prevent data errors becuase the second statement is no secure, maybe the top one already changes when the trigger runs.
I was using the top1 select this weekend and was working for some orders and for some one don't for no reason. I saw this morning that the row that I want to synchronize , the trigger do it in the next insert, this means, when Paypal order comes stay there without synchronize until the next order comes and rerun the trigger. I am using the after insert modify method and can't understand why this happens. Any ideas?
I will appreciate as well if someone give me a clue how to test Trigger or see the error log of them.

Related

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

How to create a trigger to decrease a counter, what's wrong with my trigger?

I need to decrease a counter in a table schedules, when there was an insert in enrollments table:
CREATE TRIGGER [UpdateEnrollmentsTrigger]
ON [TBLENROLLMENT_ENR]
FOR INSERT
AS
BEGIN
DECLARE #ScheduleCode NVARCHAR
DECLARE #TotalSlots INT
IF EXISTS(SELECT SCH_CODE FROM inserted)
BEGIN
SELECT #ScheduleCode = SCH_CODE FROM inserted
SELECT #TotalSlots = SCH_TOTALSLOTS FROM TBLSCHEDULES_SCH
WHERE SCH_CODE = #ScheduleCode
UPDATE TBLSCHEDULES_SCH
SET SCH_FREESLOTS = #TotalSlots - 1
WHERE SCH_CODE = #ScheduleCode
END
END
When I trying to create this trigger, the query window of VS12 says:
SQL46010 :: Incorrect syntax near ].
Thanks in advance.
The specific error is because you are using FOR INSERT instead of AFTER INSERT, but there are other things that you should improve on your trigger.
First of all, always, always write the length of a NVARCHAR, leaving it blank will behave differently depending where it's used. So replace DECLARE #ScheduleCode NVARCHAR with DECLARE #ScheduleCode NVARCHAR(n), where n is the required length.
I'm also not sure why you are doing the IF EXISTS since it's reading the INSERTED pseudo table, that it's bound to have records because the trigger was fired.
Another thing to improve is that you are assuming that only one row was inserted, as you are storing it on a variable, that's wrong and it will behave incorrectly if you insert more than just one row.
Oh, I almost forgot, you should also always specify the schema, for instance: CREATE TRIGGER [UpdateEnrollmentsTrigger] ON [TBLENROLLMENT_ENR] should be CREATE TRIGGER dbo.[UpdateEnrollmentsTrigger] ON dbo.[TBLENROLLMENT_ENR] (using the correct schema, of course)

SQL Server 2008 Trigger Errors

I need some help with a database trigger that I just can't get working. Disclosure : I'm not a DBA and don't claim any expertise, but I've been tasked with getting this done..
That said, here is the problem statement:
I have a database with a few tables that we want to track updates/inserts/deletes on. The trigger should catch the "before" and the "after" values of some columns, take both along with some additional information (mentioned below) and add them to a versioncontrol table.
I've put together what I think should work based on tutorial and other information available on various sites, but no matter what I do when I try to create the trigger it always throws an error:
Msg 311, Level 16, State 1, Procedure tr_taskconstructs_U, Line 38
Cannot use text, ntext, or image columns in the 'inserted' and 'deleted' tables.
The column layout for the table I'm applying the trigger to is very simple:
ResourceID (PK, nvarchar(38))
AML (ntext, null)
I want to catch changes to the AML column and insert the changes into a table, as follows:
id (int, not null),
ResourceID (nvarchar(38)),
TableName (nvarchar(50)),
DateTime (datetime),
Type (varchar(20)),
Before (ntext),
After (ntext)
My code is as follows:
CREATE TRIGGER tr_taskconstructs_U ON taskconstructs AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #before nvarchar(max),
#after nvarchar(max),
#resource nvarchar(50)
IF UPDATE(AML)
BEGIN
SELECT #before = d.AML,
#after = i.AML,
#resource = d.ResourceID
FROM inserted i
INNER JOIN deleted d on d.ResourceID = i.ResourceID
INSERT INTO versioncontrol
VALUES (#resource, 'taskconstructs', GetDate(), 'Update', #before, #after)
END
END
GO
It always fails with the error mentioned above. I tried changing the datatypes of the variables, etc, with the same result. I've tried commenting out almost everything and it also has the same error. I'm obviously missing something, but am not able to figure out what.
Any help would be appreciated.
change the table to use the nvarchar(max) datatype instead. Ntext is deprecated anyhow and should not be used going forward
Like said in the other answer ntext, along with text and image are deprecated datatypes which triggers can't really work with. They will be removed for future versions of SQL Server so your best solution would be to change them to NVARCHAR(MAX), VARCHAR(MAX) or VARBINARY(MAX) respectively.
http://msdn.microsoft.com/en-us/library/ms189799.aspx
However, if that's not a possibility for you at the moment - INSTEAD OF trigger can work with them so you can try to intercept the updates and do them from trigger, filling your log table in the process.
But, before I show you example of that, I must point out a big mistake you have in your existing trigger - You have wrote the query that works only on single row from INSERTED which is not good as UPDATE can often update more then 1 row at the time. Even if your app is not designed to allow it, you should never write trigger asuming it is always going to be single row.
So your trigger should have looked like this:
(and should look like this if/after you change that column)
CREATE TRIGGER tr_taskconstructs_U ON taskconstructs AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF UPDATE(AML)
BEGIN
INSERT INTO versioncontrol
SELECT ResourceID, 'taskconstructs', GetDate(), 'Update'. d.AML, i.AML
FROM inserted i
INNER JOIN deleted d on d.ResourceID = i.ResourceID
END
END
GO
Now, for the INSTEAD OF TRIGGER:
CREATE TRIGGER tr_taskconstructs_U ON taskconstructs INSTEAD OF UPDATE
AS
BEGIN
--insert log
INSERT INTO versioncontrol
SELECT i.ResourceID, 'taskconstructs', GetDate(), 'Update', d.AML, i.AML
FROM inserted i
INNER JOIN taskconstructs d on d.ResourceID = i.ResourceID
--update actual data
UPDATE t
SET t.AML = i.AML
from taskconstructs t
INNER JOIN INSERTED i ON i.ResourceID = t.ResourceID
END
GO
SQLFiddle DEMO

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 update trigger

I want a SQL trigger to fire when a table is updated. I have a table called SimActivation and a stored procedure called spUpdateMnpDate that takes two parameters, msisdn(varchar) and date(datetime).
When the SimActivation table is updated I want to call the procedure with the new values.
Here is what I got at the moment, after changing it back and forth:
USE StoreSale;
GO
CREATE TRIGGER dbo.tSyncMnpDate
ON [dbo].[SimActivation]
AFTER UPDATE
AS
DECLARE #date datetime
DECLARE #msisdn varchar(10)
SET #date = (select ProcessDate from inserted)
SET #msisdn = (select Msisdn from inserted)
EXEC [spUpdateMnpDate]
#msisdn, #date;
GO
Can anyone point me in the right direction?
Thanks :)
The problem you have is that a trigger will fire when one or more rows have been updated. At the moment you are assuming your trigger will fire for each row, which is not the case in SQL Server.
If the stored procedure you are trying to call is fairly simple I'd pull the code out of there and in to the trigger. But remember you are working with sets of changed rows (even if the change is to only one row) so you have to write your SQL accordingly.
EDIT: I assume your procedure is updating a date where the PK is equal to #msisdn, if so you can do this in your trigger:
UPDATE Your_Table
SET Your_Table.ProcessDate = inserted.ProcessDate
FROM Your_table INNER JOIN inerted ON Your_Table.Msisdn = inserted.Msisdn
Joining the tables ensures it will work for one or many updated rows.