I need to execute a query before every insert into the table. I try to use instead of
--insert into tbl_Exlog(ActionName) values('Insert')
--select * from tbl_Exlog
ALTER Trigger [dbo].[trgExLogTest] on [dbo].[tbl_ExLog]
Instead of Insert
as
begin
insert into tbl_ExLog (ActionName) values('trigger')
end
but it restricts the actual insert which I don't want.
Output :
ActionName
trigger
Insert is missing
The INSERT is missing, yes, in your TRIGGER. You never told SQL Server to INSERT the data, so it doesn't INSERT it. An INSTEAD OF INSERT "does exactly what it says on the tin"; 'do this instead of the INSERT'. You tell SQL Server to INSERT a row into tbl_ExLog instead but don't tell it to INSERT into the table you were actually inserting again.
Define the INSERT in your trigger:
ALTER TRIGGER [dbo].[trgExLogTest] ON [dbo].[tbl_ExLog]
INSTEAD OF INSERT AS
BEGIN
INSERT INTO dbo.tbl_ExLog (ActionName) VALUES ('trigger');
INSERT INTO dbo.trgExLogTest ({Column List})
SELECT {Column List}
FROM inserted;
END;
Related
In oracle i create triggers without problems, but in tsql i heave one big problem :)
I have a job, who insert rows into one tabel:
SELECT wa.IdAnkiety
,wa.IdUsterkiService
,wa.LiczbaGlosowTak
,wa.LiczbaGlosowNie FROM [SERV-SQL01].[DomTransfer].[dbo].[D5Cts_WynikiAnkiet] wa where not
exists (select wy.IdUsterkiService from dba.DOM_WyAnkiet wy
where wy.IdUsterkiService=wa.IdUsterkiService and
wy.IdAnkiety=wa.IdAnkiety)```
And on this: dba.DOM_WyAnkiet tble I heave a trigger
ALTER trigger [dba].[wyankiet]
on [dba].[DOM_WyAnkiet] AFTER insert
AS
begin
declare #DefectActId uniqueidentifier,
#tak int,
#nie int;
select #DefectActId=IdUsterkiService, #tak=tak, #nie=nie from inserted;
if #tak>#nie
update dba.DefectAct set status='49A86504-2E7D-46AB-A022-FC4C3C8CA853', InspectionDate=GETDATE() where DefectActId=#DefectActId;
if #nie>#tak
update dba.DefectAct set status='2EDA9FB2-8ED2-43AC-8C30-348D3F060CE3',InspectionDate=GETDATE() where DefectActId=#DefectActId;
if #nie=#tak
update dba.DefectAct set status='588B5BAA-F7CE-455D-9489-B2B956949449',InspectionDate=GETDATE() where DefectActId=#DefectActId;
end
But seems thats nor works
in oracle i add the FOR EACH ROW command and something like here above are works.
To handle a multi-row insert. join to the inserted virtual table instead of assigning scalar variables. Below is an example (untested) of this set-based technique using a CASE expression:
ALTER trigger [dba].[wyankiet]
ON[dba].[DOM_WyAnkiet] AFTER INSERT
AS
UPDATE da
set status=
CASE
WHEN i.tak>i.nie THEN '49A86504-2E7D-46AB-A022-FC4C3C8CA853'
WHEN i.nie>i.tak THEN '2EDA9FB2-8ED2-43AC-8C30-348D3F060CE3'
WHEN i.nie=i.tak THEN '588B5BAA-F7CE-455D-9489-B2B956949449'
END
, InspectionDate=GETDATE()
FROM dba.DefectAct AS da
JOIN inserted AS i ON i.DefectActId=da.DefectActId;
Is there a way of getting the SQL code that fired a trigger from inside the fired trigger, without using DBCC INPUTBUFFER or sys.dm_exec_input_buffer?
I need this for a trigger that logs the new value, the old value and the statement that made the change in that table.
Even though DBCC INPUTBUFFER resolves the challenge, I cannot use it because I need to use "INSERT INTO ... EXEC" in order to get the query that fired the trigger and the trigger is fired by many statements that already use "INSERT INTO ... EXEC", so I will get the error
An INSERT EXEC statement cannot be nested
From my research, sys.dm_exec_input_buffer might do the trick, but I cannot use it since it is available only for SQL Server 2014 SP4 and newer (as mentioned here: Get last command in SQL Server without DBCC INPUTBUFFER), and I am using an older version.
I have tried several ways of solving the problem but without success. I cannot get the SQL statement that fired the trigger but only the last executing statement which is the trigger.
To see the problem, take a look at the following code:
--Create the table that will have the trigger
CREATE TABLE [dbo].[___testTrigger]
(
[text] [NVARCHAR!(50) NOT NULL
) ON [PRIMARY]
GO
CREATE TRIGGER dbo.TestTriggerAuditLog
ON dbo.___testTrigger
AFTER INSERT,DELETE,UPDATE
AS
BEGIN
SET NOCOUNT ON;
--Version 1: without "INSERT INTO ... EXEC" but does not get the text of the statement that fired the trigger. Instead, it gets the current running query, which is the trigger
SELECT sqltext.TEXT,
req.session_id,
req.status,
req.command,
req.cpu_time,
req.total_elapsed_time
FROM sys.dm_exec_requests req
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS sqltext
WHERE req.session_id = ##SPID
--Version 2: gets the statement that fired the trigger, but we need to use "INSERT INTO ... EXEC"
DECLARE #inputbuffer TABLE (EventType NVARCHAR(30),Parameters INT,EventInfo NVARCHAR(4000))
INSERT INTO #inputbuffer EXEC('dbcc inputbuffer('+##Spid+') WITH NO_INFOMSGS')
SELECT * FROM #inputbuffer AS I
END
I know that in a trigger is not ok to have SELECT statements! I did it just to make the example simpler.
Now, we can insert some data to see what we get:
--test
INSERT INTO dbo.___testTrigger (text)
VALUES (N'This is a test test')
We will get the 2 selects returning different results, as can be seen in the bellow image.
Any ideas of what could I use to get the same result as DBCC INPUTBUFFER but without using "INSERT INTO ... EXEC" and without using sys.dm_exec_input_buffer as it is not available in my SQL Server version?
create table dbo.abcd(id int);
go
create trigger dbo.triggerabc on dbo.abcd for insert, update, delete
as
begin
declare #t table(query nvarchar(4000));
insert into #t (query)
select EventInfo
from OPENROWSET('SQLNCLI', 'Server=localhost;Trusted_Connection=yes;',
'
declare #spid nvarchar(10), #sql nvarchar(1000);
select #spid = cast(session_id as nvarchar(10))
from sys.dm_exec_requests
where session_id > 50
and wait_type = ''OLEDB''
and wait_resource like ''SQLNCLI%(SPID='' + cast(##spid as varchar(10)) + '')'';
select #sql = ''dbcc inputbuffer('' + #spid + '') WITH NO_INFOMSGS'';
exec(#sql) with result sets( (EventType NVARCHAR(30),Parameters SMALLINT,EventInfo NVARCHAR(4000)) );
'
) ;
select * from #t;
end
go
insert into abcd(id) values(123)
go
insert into abcd(id)
exec('select 456')
go
drop table abcd
go
Here's a very simple solution.
But first, since triggers don't fire on select it probably isn't very accurate to refer to "queries" firing the trigger. It would probably be more accurate to call them "statements."
Anyway, add a column to your table such as StatementName varchar(10) and then in each insert statement that will fire the trigger, add a value such as 'Statement1', 'Statement2', etc.
Then the trigger can just check the inserted row and know what statement fired the trigger.
I've been googled about my problem, but I didn't find anything relevant.
I'm executing a Bulk Insert with flag FIRE_TRIGGERS enabled.
So, I need pass each row in my Bulk Insert to a procedure.
When I execute a insert row by row, my triggers works fine but when I execute a Bulk Insert my triggers don't work.
My trigger code:
ALTER TRIGGER [dbo].[tgSetDetails]
ON [PORTALSQLDB].[dbo].[BurnTimeRawData]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #ServiceTag varchar(10);
DECLARE #Platform varchar(50);
SELECT
#ServiceTag = ServiceTag,
#Platform = Platform
FROM
inserted
EXEC spBurnTimeInsertData #ServiceTag, #Platform
END
Any idea how I can do this job?
Thanks :)
This trigger will fire once for each insert statement or bulk insert batch. To call a proc for each row, you'll need a cursor.
It would be better to refactor the proc code as a set-based operation to include in the trigger code. That will perform much better.
I did a search over the net but I couldnt find my answer
in oracle , if we to specify for the trigere if its insert or update , we write like this :
create or replace trigger TRG_LOGS
after INSERT or update or delete
ON TABOE_LOGS
FOR EACH ROW
DECLARE
V_USERNAME VARCHAR2(100);
BEGIN
if inserting then
insert into long_log(NAME) VALUE (:new.NAME)
ELSE if UPDATING THEN
insert into long_log(NAME) VALUE (:OLD.NAME)
END;
END;
Is throwing an error on Incorrect syntax near the keyword 'insert'.
For Sybase, each action is a seperate trigger:
create trigger TRG_LOGS_INS on TABOE_LOGS
for INSERT
as
DECLARE #V_USERNAME varchar(100)
BEGIN
insert into long_log
select NAME from INSERTED
END
....
create trigger TRG_LOGS_UPD on TABOE_LOGS
for UPDATE
as
DECLARE #V_USERNAME varchar(100)
BEGIN
insert into long_log
select NAME from DELETED
END
Not sure if my syntax is exactly right, but should get you pointed in the right direction. The INSERTED table (similar to Oracles new) stores the new records on either an insert or update action. The DELETED table (similar to Oracles old) stores the old records on either an update or delete action.
More information and examples can be found in the Sybase T-SQL Users Guide: Triggers
What i wana do is actually process some data then insert the processed data into a new table..
but first i need to check the target table ;if empty then delete everything in the table then only insert the fresh processed data..
i'm using sql server 2008...
anyone can give me the sample sql code to create the stored procedure??
create procedure SprocName
AS
BEGIN
DECLARE #ProcessedData AS TABLE (IntColumn int, CharColumn varchar(MAX))
-- get processed data
INSERT INTO #ProcessedData (IntColumn, CharColumn)
SELECT IntValue, CharValue FROM SourceTable -- WHERE your condition
-- check target and delete
IF EXISTS (SELECT * FROM TargetTable)
BEGIN
DELETE FROM TargetTable -- WHERE your condition
END
-- insert fresh
INSERT INTO TargetTable (IntColumn, CharColumn)
SELECT IntColumn, CharColumn FROM #ProcessedData
END
Sorry code not tested ;)
Syntax for create stored procedure is here: http://msdn.microsoft.com/en-us/library/ms187926.aspx
Then you need to do a select, syntax is here: http://msdn.microsoft.com/en-us/library/ms189499.aspx
Next is an if, see: http://msdn.microsoft.com/en-us/library/ms182717.aspx
And finally an insert http://msdn.microsoft.com/en-us/library/ms174335.aspx