I am trying to capture if my SQL Query have 0 rows or multiple rows. If it has 0 rows then I will insert, if 1 will perform an update, if > 1 will perform additional analysis.
Is there a way I can see if my query resulted in x results or no results in automation anywhere?
Any assistance will be appreciated.
You can make use of if exists and if not exists and check if rows exists or not, or even if there are multiple before doing the insert.
Here is a simple example using if not exists where if the row doesn't exist on dbo.Table it will insert a row. If it already exists then the ID will be logged to an Error table.
declare #InsertID int = 5, #Name nvarchar(max) = 'some name'
if ((select count(1) from dbo.Table where ID = #InsertID) > 1) -- detect error; more than one record for an id
begin
insert into dbo.Error (ErrorID, ErrorDate)
select #InsertID, getdate()
end
else if not exists (select 1 from dbo.Table where ID = #InsertID) -- no record exists for ID, insert it
begin
insert into dbo.Table (ID, Name)
select #InsertID, #Name
else if exists (select 1 from dbo.Table where ID = #InsertID) -- update the single record
begin
update dbo.Table set Name = #Name where ID = #InsertID
end
A2019 returns the results of a SQL Query as a table...
You could have an if statement right after your query which checks to see if the row count of the returned table is > 0 then take action accordingly.
looking a bit of direction or guidance as to why I’m getting multiple rows using my trigger. Basically I have a web app that controls Asset Types (i.e Laptops, Phones etc), what I’m trying to do with this trigger is when the Asset Type Name (at_typedesc) changes that I log to an audit table (in this case sql_log) what the old name was and what the new name is.
This is working, but for some reason I get multiple lines written at the INSERT TO SQL_LOG statement. It does write the old name & new name, but then I’ll get 3 additional rows which has the old name showing the new name...
This is currently on a 2008 SQL Server.
-- create the trigger
go
create trigger trg_InsteadOfUpdate on [dbo].[lkp_asset_types]
instead of update
as
begin
DECLARE #triggerAction varchar(1)
-- determine the TRIGGER action
-- this allows us to tell if its an INSERT or an UPDATE
SELECT #triggerAction = CASE
WHEN EXISTS(SELECT 1 FROM INSERTED)
AND EXISTS(SELECT 1 FROM deleted) THEN 'U'
WHEN EXISTS(SELECT 1 FROM inserted) THEN 'I'
ELSE 'D' END;
-- get the orginally asset name from the DELETED table
-- this contains the rows as they were BEFORE the UPDATE Statement
DECLARE #orgAssetTypeName varchar(255)
SET #orgAssetTypeName = (SELECT top 1 at_typedesc from lkp_asset_types WHERE at_id = (select at_id from deleted))
-- UPDATE to the new asset name based on the NEW value in the INSERTED Table
update lkp_asset_types
set at_typedesc = (select at_typedesc from inserted)
where at_id = (select at_id from inserted)
-- get the new asset name from the INSERTED table
-- this contains the rows as they were AFTER the UPDATE Statement
DECLARE #newAssetTypeName varchar(255)
SET #newAssetTypeName = (SELECT top 1 at_typedesc from lkp_asset_types WHERE at_id = (select at_id from inserted))
insert into sql_log
(sql_log)
values ('SQL PRE Changed from : ' + #orgAssetTypeName + ' to: ' + #newAssetTypeName + '. Action = ' + #triggerAction)
end
go
Logic like this in a trigger in SQL Server is just broken:
where at_id = (select at_id from inserted)
I really wish the SQL Server parser issued a warning when encountering such constructs.
There is no guarantee that inserted has only one value (nor deleted).
That is how SQL Server defines triggers: as set operations. If multiple rows are inserted at the same, then the inserted and deleted "tables" have multiple rows.
That part is simple. You will need to rewrite the trigger to take this into account.
On checking my web code the update button was performing additional updates, this caused the trigger to fire more than once thus causing duplicate rows.
create table dbo.lkp_asset_types_test
(
at_id int identity,
at_typedesc varchar(100)
)
go
create trigger trg_InsteadOfUpdate_test on [dbo].[lkp_asset_types_test]
instead of update
as
begin
select 'trigger fired!!!!'
if not exists(select * from inserted)
and not exists(select * from deleted)
begin
return;
end
--update (maybe only the diffs?)
update t
set at_typedesc = i.at_typedesc
from dbo.lkp_asset_types_test as t
join inserted as i on t.at_id = i.at_id;
--where t.at_typedesc <> i.at_typedesc & nulls??
--insert into sql_log(sql_log)
select
'SQL PRE Changed from : ' + isnull(d.at_typedesc, '*null*') + ' to: ' + isnull(i.at_typedesc, '*null*') + '. Action = U'
from inserted as i
join deleted as d on i.at_id = d.at_id
--where i.at_typedesc <> d.at_typedesc & nulls ??
end
go
insert into dbo.lkp_asset_types_test(at_typedesc) values ('A'), ('B'), ('C'), ('D'), (NULL);
go
update dbo.lkp_asset_types_test
set at_typedesc = case when at_id%2=0 then isnull(at_typedesc, 'X') else isnull(at_typedesc, '') + 'xyz' end
go
select *
from dbo.lkp_asset_types_test;
go
update dbo.lkp_asset_types_test
set at_typedesc = case when at_id%2=0 then at_typedesc else at_typedesc + 'xyz' end
where 1=2
go
--
drop table lkp_asset_types_test;
I have a update trigger for update status column value change and update other table record and it is working fine. Here is my code
CREATE TRIGGER [dbo].[trgAfterUpdate] ON [dbo].[recharge_request]
FOR UPDATE
AS
DECLARE #status varchar(50);
SELECT #status=i.status FROM inserted i;
IF UPDATE (status)
BEGIN
IF #status='Failure'
--My Update Statement
ELSE IF #status='Success'
--My Update Statement
END
Now I'm want to create an insert trigger also for check status column value and perform other table operation. because in some case status column value will not been update to I need to perform some operation on insert if column value is 'Success' or 'Fail'. status column possible values are 'Success', 'Fail', 'Pending' and 'Process'. any help will be appreciated. Thanks in advance!
DECLARE #status varchar(50);
SELECT #status=i.status FROM inserted i;
you are not handling cases where multiple rows are being updated.
You need to treat the inserted and deleted as a table that may contains more than 1 row
IF UPDATE (status)
BEGIN
update t
set ....
from inserted i
inner join some_table t on i.somecol = t.anothercol
where t.status = 'Failure'
update t
set ....
from inserted i
inner join some_table t on i.somecol = t.anothercol
where t.status = 'Success'
. . . . . -- other status value
END
My Issue has been resolved here is solution:
CREATE TRIGGER [dbo].[trgAfterInsert] ON [dbo].[recharge_request]
AFTER INSERT
AS
BEGIN
DECLARE #status varchar(50);
SELECT #status=i.status FROM inserted i;
IF #status='Success'
BEGIN
--My Update statement
END
END
Which is the right syntax in order to create two or more triggers in a row by executing a query with SQL Server?
I tried the following one:
GO
CREATE TRIGGER TRG_MyTable_UpdatedAt
ON dbo.MyTable
AFTER UPDATE
AS
UPDATE dbo.MyTable
SET UpdatedAt = GETDATE()
WHERE ID IN (SELECT DISTINCT ID FROM Inserted)
END
GO
CREATE TRIGGER TRG_MyTable_CreatedAt
ON dbo.MyTable
AFTER INSERT
AS
UPDATE dbo.MyTable
SET CreatedAt = GETDATE()
WHERE ID IN (SELECT DISTINCT ID FROM Inserted)
END
But it returns an error: Incorrect syntax near 'END'.
CREATE TRIGGER TRG_MyTable_UpdatedAt
ON dbo.MyTable
AFTER UPDATE
AS
BEGIN
UPDATE dbo.MyTable
SET UpdatedAt = GETDATE()
WHERE ID IN (SELECT DISTINCT ID FROM Inserted)
END
GO
CREATE TRIGGER TRG_MyTable_CreatedAt
ON dbo.MyTable
AFTER INSERT
AS
BEGIN
UPDATE dbo.MyTable
SET CreatedAt = GETDATE()
WHERE ID IN (SELECT DISTINCT ID FROM Inserted)
END
GO
You're missing the matching BEGIN, hence the error being near END. For example;
CREATE TRIGGER TRG_MyTable_UpdatedAt
ON dbo.MyTable
AFTER UPDATE
AS
BEGIN
UPDATE dbo.MyTable
SET UpdatedAt = GETDATE()
WHERE ID IN (SELECT DISTINCT ID FROM Inserted)
END
You forgot to write 'Begin'
CREATE TRIGGER TRG_MyTable_UpdatedAt
ON dbo.MyTable
AFTER UPDATE
AS
Begin
UPDATE dbo.MyTable
SET UpdatedAt = GETDATE()
WHERE ID IN (SELECT DISTINCT ID FROM Inserted)
END
GO
CREATE TRIGGER TRG_MyTable_CreatedAt
ON dbo.MyTable
AFTER INSERT
AS
Begin
UPDATE dbo.MyTable
SET CreatedAt = GETDATE()
WHERE ID IN (SELECT DISTINCT ID FROM Inserted)
END
GO
I have a problem with this trigger. I would like it to update the requested information
only to the row in question (the one I just updated) and not the entire table.
CREATE TRIGGER [dbo].[after_update]
ON [dbo].[MYTABLE]
AFTER UPDATE
AS
BEGIN
UPDATE MYTABLE
SET mytable.CHANGED_ON = GETDATE(),
CHANGED_BY=USER_NAME(USER_ID())
How do I tell the trigger that this applies only to the row in question?
Here is my example after a test
CREATE TRIGGER [dbo].UpdateTasadoresName
ON [dbo].Tasadores
FOR UPDATE
AS
UPDATE Tasadores
SET NombreCompleto = RTRIM( Tasadores.Nombre + ' ' + isnull(Tasadores.ApellidoPaterno,'') + ' ' + isnull(Tasadores.ApellidoMaterno,'') )
FROM Tasadores
INNER JOIN INSERTED i ON Tasadores.id = i.id
The inserted special table will have the information from the updated record.
Try this (update, not after update)
CREATE TRIGGER [dbo].[xxx_update] ON [dbo].[MYTABLE]
FOR UPDATE
AS
BEGIN
UPDATE MYTABLE
SET mytable.CHANGED_ON = GETDATE()
,CHANGED_BY = USER_NAME(USER_ID())
FROM inserted
WHERE MYTABLE.ID = inserted.ID
END
you can call INSERTED, SQL Server uses these tables to capture the data of the modified row before and after the event occurs.I assume in your table the name of the key is Id
I think the following code can help you
CREATE TRIGGER [dbo].[after_update]
ON [dbo].[MYTABLE]
AFTER UPDATE
AS
BEGIN
UPDATE dbo.[MYTABLE]
SET dbo.[MYTABLE].CHANGED_ON = GETDATE(),
dbo.[MYTABLE].CHANGED_BY = USER_NAME(USER_ID())
FROM INSERTED
WHERE INSERTED.Id = dbo.[MYTABLE].[Id]
END
You should be able to access the INSERTED table and retrieve ID or table's primary key. Something similar to this example ...
CREATE TRIGGER [dbo].[after_update] ON [dbo].[MYTABLE]
AFTER UPDATE AS
BEGIN
DECLARE #id AS INT
SELECT #id = [IdColumnName]
FROM INSERTED
UPDATE MYTABLE
SET mytable.CHANGED_ON = GETDATE(),
CHANGED_BY=USER_NAME(USER_ID())
WHERE [IdColumnName] = #id
Here's a link on MSDN on the INSERTED and DELETED tables available when using triggers: http://msdn.microsoft.com/en-au/library/ms191300.aspx
It is very simple to do that,
First create a copy of your table that your want keep the log for
For example you have Table dbo.SalesOrder with columns SalesOrderId, FirstName,LastName, LastModified
Your Version archieve table should be dbo.SalesOrderVersionArchieve with columns SalesOrderVersionArhieveId, SalesOrderId, FirstName,LastName, LastModified
Here is the how you will set up a trigger on SalesOrder table
USE [YOURDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Karan Dhanu
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE TRIGGER dbo.[CreateVersionArchiveRow]
ON dbo.[SalesOrder]
AFTER Update
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO dbo.SalesOrderVersionArchive
SELECT *
FROM deleted;
END
Now if you make any changes in saleOrder table it will show you the change in VersionArchieve table
try this solution.
DECLARE #Id INT
DECLARE #field VARCHAR(50)
SELECT #Id= INSERTED.CustomerId
FROM INSERTED
IF UPDATE(Name)
BEGIN
SET #field = 'Updated Name'
END
IF UPDATE(Country)
BEGIN
SET #field = 'Updated Country'
END
INSERT INTO CustomerLogs
VALUES(#Id, #field)
// OR
-- If you wish to update existing table records.
UPDATE YOUR_TABLE SET [FIELD]=[VALUE] WHERE {CONDITION}
I didn't checked this with older version of sql server but this will work with sql server 2012.
Try this script to create a temporary table TESTTEST and watch the order of precedence as the triggers are called in this order: 1) INSTEAD OF, 2) FOR, 3) AFTER
All of the logic is placed in INSTEAD OF trigger and I have 2 examples of how you might code some scenarios...
Good luck...
CREATE TABLE TESTTEST
(
ID INT,
Modified0 DATETIME,
Modified1 DATETIME
)
GO
CREATE TRIGGER [dbo].[tr_TESTTEST_0] ON [dbo].TESTTEST
INSTEAD OF INSERT,UPDATE,DELETE
AS
BEGIN
SELECT 'INSTEAD OF'
SELECT 'TT0.0'
SELECT * FROM TESTTEST
SELECT *, 'I' Mode
INTO #work
FROM INSERTED
UPDATE #work SET Mode='U' WHERE ID IN (SELECT ID FROM DELETED)
INSERT INTO #work (ID, Modified0, Modified1, Mode)
SELECT ID, Modified0, Modified1, 'D'
FROM DELETED WHERE ID NOT IN (SELECT ID FROM INSERTED)
--Check Security or any other logic to add and remove from #work before processing
DELETE FROM #work WHERE ID=9 -- because you don't want anyone to edit this id?!?!
DELETE FROM #work WHERE Mode='D' -- because you don't want anyone to delete any records
SELECT 'EV'
SELECT * FROM #work
IF(EXISTS(SELECT TOP 1 * FROM #work WHERE Mode='I'))
BEGIN
SELECT 'I0.0'
INSERT INTO dbo.TESTTEST (ID, Modified0, Modified1)
SELECT ID, Modified0, Modified1
FROM #work
WHERE Mode='I'
SELECT 'Cool stuff would happen here if you had FOR INSERT or AFTER INSERT triggers.'
SELECT 'I0.1'
END
IF(EXISTS(SELECT TOP 1 * FROM #work WHERE Mode='D'))
BEGIN
SELECT 'D0.0'
DELETE FROM TESTTEST WHERE ID IN (SELECT ID FROM #work WHERE Mode='D')
SELECT 'Cool stuff would happen here if you had FOR DELETE or AFTER DELETE triggers.'
SELECT 'D0.1'
END
IF(EXISTS(SELECT TOP 1 * FROM #work WHERE Mode='U'))
BEGIN
SELECT 'U0.0'
UPDATE t SET t.Modified0=e.Modified0, t.Modified1=e.Modified1
FROM dbo.TESTTEST t
INNER JOIN #work e ON e.ID = t.ID
WHERE e.Mode='U'
SELECT 'U0.1'
END
DROP TABLE #work
SELECT 'TT0.1'
SELECT * FROM TESTTEST
END
GO
CREATE TRIGGER [dbo].[tr_TESTTEST_1] ON [dbo].TESTTEST
FOR UPDATE
AS
BEGIN
SELECT 'FOR UPDATE'
SELECT 'TT1.0'
SELECT * FROM TESTTEST
SELECT 'I1'
SELECT * FROM INSERTED
SELECT 'D1'
SELECT * FROM DELETED
SELECT 'TT1.1'
SELECT * FROM TESTTEST
END
GO
CREATE TRIGGER [dbo].[tr_TESTTEST_2] ON [dbo].TESTTEST
AFTER UPDATE
AS
BEGIN
SELECT 'AFTER UPDATE'
SELECT 'TT2.0'
SELECT * FROM TESTTEST
SELECT 'I2'
SELECT * FROM INSERTED
SELECT 'D2'
SELECT * FROM DELETED
SELECT 'TT2.1'
SELECT * FROM TESTTEST
END
GO
SELECT 'Start'
INSERT INTO TESTTEST (ID, Modified0) VALUES (9, GETDATE())-- not going to insert
SELECT 'RESTART'
INSERT INTO TESTTEST (ID, Modified0) VALUES (10, GETDATE())--going to insert
SELECT 'RESTART'
UPDATE TESTTEST SET Modified1=GETDATE() WHERE ID=10-- gointo to update
SELECT 'RESTART'
DELETE FROM TESTTEST WHERE ID=10-- not going to DELETE
SELECT 'FINISHED'
SELECT * FROM TESTTEST
DROP TABLE TESTTEST
First off, your trigger as you already see is going to update every record in the table. There is no filtering done to accomplish jus the rows changed.
Secondly, you're assuming that only one row changes in the batch which is incorrect as multiple rows could change.
The way to do this properly is to use the virtual inserted and deleted tables: http://msdn.microsoft.com/en-us/library/ms191300.aspx
Trigger
special kind of stored procedure
automatically execured/fired when some event Insert/Update/Delete Occures
use when we want some event to happen automatically on certain desirable scenarios
triggers makes use of 2 tables inserted/deleted table in ssms(memory)
ONLY availabe in context of trigger(CANNOT ACCESS Outside the Trigger
when we insert/delete using trigger, a copy of row is maintained in the inserted/deleted table
inserted table - contains updated data |
deleted table - contains old data
Trigger to Update "ModifiedOn" Date Automatically when record in table is modified(UPDATED)
CREATE TRIGGER [dbo].[Trg_TableName_UpdateModifiedOn]
ON [dbo].[TableName]
AFTER UPDATE
AS
BEGIN
UPDATE [dbo].[TableName]
SET [ModifiedOn] = GetDate()
FROM [inserted]
WHERE [inserted].[PrimaryKey] = [dbo].[TableName].[PrimaryKey];
END;
CREATE TRIGGER [dbo].[after_update] ON [dbo].[MYTABLE]
AFTER UPDATE
AS
BEGIN
DECLARE #ID INT
SELECT #ID = D.ID
FROM inserted D
UPDATE MYTABLE
SET mytable.CHANGED_ON = GETDATE()
,CHANGED_BY = USER_NAME(USER_ID())
WHERE ID = #ID
END