T-SQL (SQL Server 2016) trigger for column value alter, at Insert - sql

I am working on a SSIS project of mine. I have successfully manage to load some csv's into my database (through Integration Services in VS) and now I am trying to create a trigger in the database.
All I want to happen is: when the number of the column second_road_class is -1 I want it to change into 6. I want the trigger to fire during the inserts.
My trigger code seems to debug ok in SSMS! But when I am later trying to insert the csv's again, the second_road_class column with -1 stays as it is.
Trigger code:
CREATE TRIGGER AccidentsTrigger
ON [Accidents]
INSTEAD OF INSERT
AS BEGIN
SET NOCOUNT ON
IF (SELECT [second_road_class] FROM INSERTED) LIKE '-1'
BEGIN
UPDATE [Accidents]
SET [second_road_class] = '6'
WHERE [second_road_class] = '-1'
END
END
Thanks for any help.

You could do this with an after insert trigger.
create trigger accidentstrigger on [accidents]
after insert as
begin;
set nocount on;
if exists (select 1 from inserted where [second_road_class] = '-1')
begin;
update a
set [second_road_class] = '6'
from [accidents] as a
inner join inserted i
/* change AccidentId to the Primary Key on accidents*/
on a.AccidentId = i.AccidentId
and i.[second_road_class] = '-1';
end;
end;
go
Example using the pilots table on rextester: http://rextester.com/XKX10184

Related

Creating an update trigger is causing an error

There are two triggers; the first trigger is running perfectly but I want to add another trigger to the same table.
The second trigger is an after update trigger. Please check and tell my is it right or wrong or if we run this trigger it will run perfect or not
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[tr_issueBook]
ON [dbo].[IssueBooks]
FOR INSERT
AS
BEGIN
DECLARE #IsbnNumber varchar(255)
SELECT #IsbnNumber = ISBN_Number FROM inserted
UPDATE searchBooks
SET tbl_numberOfCopies = tbl_numberOfCopies - 1
WHERE tbl_IsbnBooks = #IsbnNumber
END
/******2nd Trigger ******/
CREATE TRIGGER [dbo].[tr_issueBook2]
ON [dbo].[IssueBooks]
AFTER UPDATE
AS
BEGIN
DECLARE #IsbnNumber varchar(255)
SELECT #IsbnNumber = BookTitle FROM updated
UPDATE searchBooks
SET tbl_numberOfCopies = [tbl_numberOfCopies] + 1
WHERE tbl_bookTitle = #IsbnNumber
END
My second trigger is throwing an error:
invalid object name updated
Both of your triggers are currently broken because you do not handle the case when the Inserted pseudo table has more or less rows than 1. You need to treat the Inserted pseudo table like you would any other table and perform set based operations on it instead of procedural logic.
-- INSERT Trigger - using the Inserted pseudo table
update searchBooks set
tbl_numberOfCopies = tbl_numberOfCopies - 1
where tbl_IsbnBooks in (select ISBN_Number from Inserted);
-- UPDATE Trigger - also using the Inserted pseudo table (There is no Updated table)
update searchBooks set
tbl_numberOfCopies = tbl_numberOfCopies + 1
where tbl_IsbnBooks in (select ISBN_Number from Inserted);
I highly recommend reading the Official Documentation.

To write a trigger for INSERT as well as UPDATE in SQL

I have written a trigger which should fire when an INSERT or UPDATE happens to a table "COST_HDR" and the DML should update one of the columns of this table i.e. "CMPL_STS" to 'C'.
My trigger is not working as expected. If the CMPL_STS is directly updated to 'C' as a new record, trigger works as expected. But if it is updated to 'D' as a new record and then to 'C' as an update, trigger fails to insert any record in TMP_XNS table.
Can anyone check what is wrong:
CREATE TRIGGER MyTrigger
ON [COST_HDR]
AFTER INSERT, UPDATE
AS
BEGIN
DECLARE #UpdtStamp DATETIME = GETUTCDATE()
--
IF UPDATE (CMPL_STS)
BEGIN
INSERT INTO [TMP_XNS]
(
HDR_UID,
UPDT_STAMP
)
SELECT I.HDR_UID,
#updtStamp
FROM INSERTED I
LEFT OUTER JOIN DELETED D
ON D.HDR_UID = I.HDR_UID
AND ISNULL(I.CMPL_STS,'N') <> ISNULL(D.CMPL_STS,'N')
WHERE I.CMPL_STS = 'C'
END
--
END
GO

Trigger preventing a column from being updated

I have created a trigger as below:
CREATE TRIGGER InsertUpdateATLastViewedMatch
ON dbo.AT_LastViewedMatch
FOR INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
-- update statements for trigger here
declare #id1 int, #matchFK int;
select #id1 = i.id from inserted i;
select #matchFK=i.AT_MatchFk from inserted i;
update dbo.AT_LastViewedMatch set matchId = #matchFK where id = #id1;
END
GO
While this trigger works- I am not able to update the value of the matchId column directly from SQLManager:
If I execute
UPDATE AT_LastViewedMatch set matchId='1179619' where id=5762
for example, I am still seeing the old value for matchId. I think the issue is related to the above trigger (since if I drop the trigger, it works). Is there a way to get past this?
From your trigger definition below, you have created it for insert and update
CREATE TRIGGER InsertUpdateATLastViewedMatch
ON dbo.AT_LastViewedMatch
FOR INSERT,UPDATE <-- Here
so essentially, whenever you are running an update statement from SSMS
UPDATE AT_LastViewedMatch set matchId='1179619' where id=5762
Your trigger performing the below line and setting it to old value
update dbo.AT_LastViewedMatch set matchId = #matchFK where id = #id1;
You need to remove that update from your trigger definition
CREATE TRIGGER InsertUpdateATLastViewedMatch
ON dbo.AT_LastViewedMatch
FOR INSERT

how to create before update trigger in sql server 2005

Is there anyway where I can create a trigger which will execute before the update/delete takes place( and then the actual update/delete takes place)? and how can I drop a trigger from a table?
to drop a trigger use:
--SQL Server 2005+, drop the trigger, no error message if it does not exist yet
BEGIN TRY DROP TRIGGER dbo.TrigerYourTable END TRY BEGIN CATCH END CATCH
GO
--drop trigger pre-SQl Server 2005, no error message if it does not exist yet
if exists (select * from sysobjects where id = object_id(N'[dbo].[TrigerYourTable ]') and OBJECTPROPERTY(id, N'IsTrigger') = 1)
drop trigger [dbo].[TrigerYourTable ]
GO
OP said in a comment:
...suppose I have to check childcount of
a perticular user if that is more than
5 do not update the user.how can I do
that using instead of trigger?
You don't really need to prevent the original update, you can let it happen, and then in the trigger check for the problem and rollback if necessary. This is how to enforce the logic for one or many affected rows, when you need to JOIN to determine the childcount of the affected rows:
--create the trigger
CREATE TRIGGER dbo.TrigerYourTable ON dbo.YourTable
AFTER UPDATE
AS
SET NOCOUNT ON
IF EXISTS (SELECT
1
FROM INSERTED i
INNER JOIN YourChildrenTable c ON i.ParentID=c.ParentID
GROUP BY i.ParentID
HAVING COUNT(i.ParentID)>5
)
BEGIN
RAISERROR('Count of children can not exceed 5',16,1)
ROLLBACK
RETURN
END
GO
It will throw the error if there is a violation of the logic, and the original command will be subject to a rollback.
If childcount is a column within the affected table, then use a trigger like this to enforce the logic:
--create the trigger
CREATE TRIGGER dbo.TrigerYourTable ON dbo.YourTable
AFTER UPDATE
AS
SET NOCOUNT ON
IF EXISTS (SELECT 1 FROM INSERTED WHERE childcount>5)
BEGIN
RAISERROR('Count of children can not exceed 5',16,1)
ROLLBACK
RETURN
END
GO
If you just want to ignore the update for any rows that violate the rule try this:
--create the trigger
CREATE TRIGGER dbo.TrigerYourTable ON dbo.YourTable
INSTEAD OF UPDATE
AS
SET NOCOUNT ON
UPDATE y
SET col1=i.col1
,col2=i.col2
,col3=i.col3
,.... --list all columns except the PK column!
FROM dbo.YourTable y
INNER JOIN INSERTED i on y.PK=i.PK
WHERE i.childcount<=5
GO
It will only update rows that have a child count less than 5, ignoring all affected rows that fail the requirement (no error message).
This article from microsoft explains the syntax of creating triggers.
http://msdn.microsoft.com/en-us/library/ms189799.aspx
There isn't really a 'before' trigger, but you can use an INSTEAD OF trigger that allows you to jump in place of whatever action is attempted, then define your own action.
I've used that technique for versioning data.
CREATE TRIGGER [dbo].[Documents_CreateVersion]
ON [dbo].[Documents]
INSTEAD OF UPDATE
AS
BEGIN
DECLARE #DocumentID int
SELECT DocumentID = DocumentID FROM INSERTED
-- do something
END
INSERTED is a bit of a misnomer here, but it contains the details of the action before it occurs you can then define your own action with that data.
Edit:
As per comments below my response, my example can be dangerous if multiple rows are updated at once. My application doesn't allow for this so it's fine in this case. I would agree that the above is a bad practice regardless.
to drop trigger- use database_name
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'tgr_name' AND type = 'TR')
DROP TRIGGER tgr_name
GO
Here's a simple trigger that checks columns values, and fires before updating or inserting, and raises an error.
IF OBJECT_ID ('dbo.MyTableTrigger', 'TR') IS NOT NULL
DROP TRIGGER dbo.MyTableTrigger;
GO
CREATE TRIGGER MyTableTrigger
ON dbo.MyTable
FOR INSERT, UPDATE
AS
DECLARE #Col1ID INT
DECLARE #Col2ID INT
SELECT #Col1ID = Col1ID, #Col2ID = Col2ID FROM inserted
IF ((#Col1ID IS NOT NULL) AND (#Col2ID IS NOT NULL))
BEGIN
RAISERROR ('Col1ID and Col2ID cannot both be in MyTable at the same time.', 16, 10);
END

After insert, update trigger not running

I have two triggers After Insert or Update and Instead of Insert. It appears that the after trigger is not running or sending the correct data.
I have verified the correct operation of Z_UpdateStageTable stored procedure and the Instead of Insert trigger. Removing the Instead of Insert trigger doesn't have any affect. The After Insert, Update trigger was working correctly at one time, I haven't made any changes to it. I have tried deleting it and adding it, but it still doesn't run or have the correct data.
Any Ideas?
Instead of Insert:
ALTER TRIGGER [DeleteExistingFilter]
ON [dbo].[Z_MobileSyncFilters]
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM Z_MobileSyncFilters WHERE UserID = (SELECT UserID FROM INSERTED);
INSERT INTO Z_MobileSyncFilters
SELECT *
FROM INSERTED;
END
After Insert, Update:
TRIGGER [UpdateStageTable]
ON [dbo].[Z_MobileSyncFilters]
AFTER INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #AllWos AS VARCHAR(5000);
DECLARE #PmWos AS VARCHAR(5000);
DECLARE #RepWos AS VARCHAR(5000);
SET #AllWos = (SELECT AllWos FROM INSERTED);
SET #RepWos = (SELECT AllWos FROM INSERTED);
SET #PmWos = (SELECT AllWos FROM INSERTED);
EXEC Z_UpdateStageTable #AllWos;
EXEC Z_UpdateStageTable #RepWos;
EXEC Z_UpdateStageTable #PmWos;
END
Is there a typo in the SET part of the AFTER trigger? You're selecting the same thing into three different variables.
Rather than confirming the behavior of Z_UpdateStageTable, I'd try to replace it with something dirt simple (a parameterless sql statement, say) to test whether the trigger's being called. It's possible that the sproc's not being called with what you think it's being called with.
You can add PRINT statements to the trigger and manually insert from ManagementStudio/Enterprise Manager to see where the trigger fails.
I see a problem when you insert multiple records in a single statement, as the SELECT FROM Inserted will return more than 1 record.
You can also update the SET statement to SELECT #Var = AllWos FROM Inserted
Hold on a second, if userid is your PK then Z_MobileSyncFilters will not have data yet, this is also an instead of trigger
this wholw block doesn't do anything really, why do you need this trigger?
DELETE FROM Z_MobileSyncFilters WHERE UserID = (SELECT UserID FROM INSERTED);
INSERT INTO Z_MobileSyncFilters
SELECT *
FROM INSERTED;
you second trigger is flawed because it will faile if you have a multi row operation
why do you have 2 insert trigger (1 instead 1 after) on this table?