UPDATE after INSERT for potentially multiple rows - not working - sql

I have the following trigger which doesn't work and I'm not sure why.
The trigger should fire after an insert into the REFERRALS table and I've allowed for the possibility of multiple rows being inserted.
The value of ORIGINAL_PATIENT_ID in the REFERRALS table should be set to the value of PATIENT_ID in Inserted, but it just doesn't work, i.e. the value of ORIGINAL_PATIENT_ID remains NULL.
IF EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[updateOSC]'))
DROP TRIGGER [dbo].[updateOSC]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[updateOSC]
ON [dbo].[REFERRALS]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
IF (SELECT ORIGINAL_PATIENT_ID FROM Inserted) IS NULL
UPDATE [dbo].[REFERRALS]
SET ORIGINAL_PATIENT_ID = i.PATIENT_ID
FROM Inserted i
WHERE dbo.REFERRALS.PATIENT_ID = i.PATIENT_ID
END
GO

If you can have multiple rows being updated then IF (SELECT ORIGINAL_PATIENT_ID FROM Inserted) IS NULL doesn't make much sense to me as this will return multiple values which you cannot compare to NULL.
I think you will get your desired result by using
CREATE TRIGGER [dbo].[updateOSC]
ON [dbo].[REFERRALS]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
UPDATE [dbo].[REFERRALS]
SET
ORIGINAL_PATIENT_ID = i.PATIENT_ID
FROM
Inserted i
WHERE
dbo.REFERRALS.PATIENT_ID = i.PATIENT_ID AND i.ORIGINAL_PATIENT_ID IS NULL
END
GO

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.

Delete trigger and getting field from another table

I have this delete trigger on an SQL database. The record deletes currently and gets written to an audit table. I have been asked to include in this history table a field from another table that is related to the record being deleted based on SurveyID. I thought I could do something like
select #Status = Status from table where Survey = deleted.Survey
But this is incorrect syntax.
ALTER trigger [dbo].[table_Selfdelete]
on [dbo].[table]
after delete
as
Begin
Set nocount on;
Declare #SurveyId int
Declare #StudentUIC varchar(10)
Declare #Status varchar(10)
select #SurveyId = deleted.SurveyID,
#StudentUIC = deleted.StudentUIC
from deleted
select #Status = Status from tbly when SurveyID = deleted.SurveyID
insert into fupSurveyAudit
values(#SurveyId,#StudentUIC,#Status)
End
Arrgh. I think you want this insert in your trigger (and nothing else):
insert into fupSurveyAudit(SurveyId, StudentUIC, status)
select d.SurveyId, d.StudentUIC, y.status
from deleted d left join
tbly y
on d.SurveyId = y.SurveyId;
Notes:
deleted could contain more than one row, so assuming that it has one row can lead to a run-time error or incorrect results.
A left join is needed in case there is no matching row for the status.
You should always include the columns in an insert
Your archive table should have additional columns, such as an identity column and the date of the insert, which are set automatically (and hence not explicitly part of the insert).
Triggers are fired once for each statement (Delete,insert,update) not for each row inside the statement.
You cannot use variables here because when multiple lines are deleted from the table only one line will be inserted in the Audit table because the variable can only hold one value.
You just need a simple insert from the deleted table into the Audit table something like this....
ALTER trigger [dbo].[table_Selfdelete]
on [dbo].[table]
after delete
as
Begin
Set nocount on;
insert into fupSurveyAudit(SurveyId, StudentUIC,[Status])
select d.SurveyID
,d.StudentUIC
,y.[Status]
from deleted d
INNER JOIN tbly y ON y.SurveyID = deleted.SurveyID
End
Try this
ALTER trigger [dbo].[table_Selfdelete]
on [dbo].[table]
after delete
as
Begin
Set nocount on;
insert into fupSurveyAudit -- Better listed the column list here
select
d.SurveyID, d.StudentUIC, y.Status
from
deleted d JOIN tbly y ON d.SurveyID = y.SurveyID
End

Internal Trigger to Obtain Newly Inserted Records

I am trying to execute a query but am having trouble. To start I have Table A and Table B. Table A has the following columns (RowID, ItemNumber, CaseCount, Elc, TotalElc, TimeStamp). Table B has the following columns( RowID, ItemNumber, Elc, TotalElc)
I am using a dashboard to insert values into Table A. I am inserting integers into ItemNumber, and CaseCount.
When these values are inserted, I am using an internal trigger on Table A after any inserts that have been made. The internal trigger obtains the values that were just inserted and uses the ItemNumber to lookup Table B to obtain the ELC and Totallc and insert it into Table A where the ItemNumber matches Table B.
How to obtain the values with the trigger to retrieve the newly inserted values (values being ItemNumber, CaseCount)?
Then after the values are retrieved, how to use the item numbers(will be 20 ItemNumbers inserted at once) to look up values in table B and insert them into Table A where the ItemNumber matches?
I don’t have much code since I am practically stuck on number one . Any help is most appreciated.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER ObtainValues
ON Table A
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
-- Insert statements for trigger here
END
GO
As you have created Trigger on Table A, whenever a row is insert, SQL Server will create a table called INSERTED which holds newly added rows only. The scope of this INSERTED table is within your Trigger body only.
Check the below code:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER ObtainValues
ON Table A
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE TableA
SET col1 = B.col1,
col1 = B.col1
FROM TableB B
WHERE B.ItemNumber = (SELECT ItemNumber FROM INSERTED)
END
GO
Similarly, when delete event occurs, DELETED table is created.
Taking Nithin's fine example as a starting point. I modified this so it will handle multiple row inserts.
CREATE TRIGGER ObtainValues
ON TableA
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE TableA
SET col1 = B.col1,
col1 = B.col1
FROM TableB B
INNER JOIN TableA A on a.[YourPrimaryKey] = b.[YourPrimaryKey]
SET NOCOUNT OFF;
GO

SQL Trigger & Inserted Idenities

I've got a problem with a trigger that i can't figure out.
Assume i have two tables, Stu_Table2 & Stu_log. Stu_table2 has some columns, one of which is an automatically generated primary key [stu_id]. The link between the two tables is [stu_name]=[user_id]
The below code works fine for Updates & Deletions (as the primary key already exists). But i'm stuck on the insert - how can i insert the automatically generated primary key from stu_name to log table if it hasn't been generated yet?
Stu_name columns, [stu_id] [Stu_name] [Stu_class]
Stu_log columns, [user_id] [stu_name]
obviously this isn't a real world example, just testing proof of concept.
ALTER TRIGGER [dbo].[stu_testtrigger]
ON [dbo].[Stu_Table2] FOR INSERT, UPDATE, DELETE
AS
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with caller queries SELECT statements.
-- If an update/insert/delete occurs on the main table, the number of records affected
-- should only be based on that table and not what records the triggers may/may not
-- select.
SET NOCOUNT ON;
--
-- Variables Needed for this Trigger
--
DECLARE #stu_ID int
DECLARE #stu_name varchar(15)
DECLARE #stu_class int
--
-- Determine if this is an INSERT,UPDATE, or DELETE Action
--
DECLARE #Action as char(1)
DECLARE #Count as int
SET #Action = 'I' -- Set Action to 'I'nsert by default.
SELECT #Count = COUNT(*) FROM DELETED
if #Count > 0
BEGIN
SET #Action = 'D' -- Set Action to 'D'eleted.
SELECT #Count = COUNT(*) FROM INSERTED
IF #Count > 0
SET #Action = 'U' -- Set Action to 'U'pdated.
END
if #Action = 'D'
-- This is a DELETE Record Action
--
BEGIN
SELECT #Stu_id =[stu_id]
,#Stu_name = [stu_name]
FROM DELETED
DELETE [dbo].[stu_log]
WHERE [user_id]=#stu_id
END
Else
BEGIN
--
-- Table INSERTED is common to both the INSERT, UPDATE trigger
--
SELECT #stu_id =[stu_id]
,#stu_name = [stu_name]
FROM INSERTED
if #Action = 'I'
-- This is an Insert Record Action
--
--THIS IS WHERE I'm STUCK i think!!!
BEGIN
INSERT INTO [stu_log]
([user_id]
,[description])
VALUES
(#stu_id
,#stu_name)
END
else
-- This is an Update Record Action
--
BEGIN
UPDATE [stu_log]
SET [user_id] = #stu_id
,[description] = #Stu_name
WHERE [user_id]=#stu_id
END
END
HELP!
Since you seem to want to carry out distinctly different actions for inserts, updates and deletes, I'm not sure why you're cramming all of the actions into a single trigger. I'd just have:
CREATE TRIGGER [dbo].[stu_testtrigger_I]
ON [dbo].[Stu_Table2] AFTER INSERT
AS
INSERT INTO stu_log ([user_id],[description])
SELECT stu_id,stu_name from inserted
GO
CREATE TRIGGER [dbo].[stu_testtrigger_D]
ON [dbo].[Stu_Table2] AFTER DELETE
AS
DELETE FROM stu_log WHERE [user_id] IN (
SELECT stu_id from deleted)
GO
CREATE TRIGGER [dbo].[stu_testtrigger_U]
ON [dbo].[Stu_Table2] AFTER UPDATE
AS
UPDATE l SET user_name = i.user_name
FROM
stu_log l
inner join
inserted i
on l.[user_id] = i.stu_id
GO
Notes:
This works for multi-row inserts, updates and deletes, which your original didn't
I've said AFTER instead of FOR, to make it clearer to you that these actions occur after any activity in Stu_Table2 has already occurred (e.g. the identity value has already been generated, which seems to be your concern).
You should note, however, that AFTER and FOR are synonymous. You'd only get different behaviour if we were doing an INSTEAD OF trigger.
I removed the pointless [user_id] = #stu_id setting from the UPDATE. Given the WHERE clause of this update (or my join equivalent, above), those two must already be equal.

How to create a trigger that uses INSERT , DELETE , UPDATE events

I want to create a trigger for logging.So i need event names of INSERT,UPDATE or DELETE.i.e : one of these statements is used in query execution my trigger will trig and starts logging.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER LogBuses
ON Bus_table
AFTER INSERT,DELETE
AS
BEGIN
DECLARE #PlateNo nvarchar(50)
IF INSERT//something like that-INSERTING- DELETING
SELECT #PlateNo=PlateNo from inserted
insert into Logger (EffectedTable,ActionName,EffectDate,EffectedID)
VALUES ('Bus_table','Insert',SYSDATETIME (),#PlateNo);
ELSE IF DELETE
SELECT #PlateNo=PlateNo from deleted
insert into Logger (EffectedTable,ActionName,EffectDate,EffectedID) VALUES ('Bus_table','Insert',SYSDATETIME (),#PlateNo);
END
GO
You use the inserted and deleted tables. It's inserted if just the inserted table is populated, deleted if just the deleted table is populated, and updated if both tables are populated. Use if exists (select 1 from inserted) to test.
if exists (select 1 from inserted) and exists (select 1 from deleted)
--update
else if exists (select 1 from inserted)
--insert
else if exists (select 1 from deleted)
--delete
Create a stored procedure that logs, and triggers for each event, that call the procedure, passing the needed data.