Reputation: 815
I have an employee table (em) that contains, among other things, a floor Id (fl_id) and room Id (rm_id). In certain circumstances (when em_loc_cnt = 0) I want to set the em record's fl_id and rm_id to null. Below is my code so far.
I am not sure how to refer to the fl_id & rm_id in the commented line. Will I run into issues because this trigger is being called as a result of the em record being updated and I am updating that same record in the trigger?
Suggestions?
IF EXISTS (SELECT * FROM [sysobjects] WHERE [name] = 'em_upd_self_serv_t' AND [type] = 'TR')
BEGIN
DROP TRIGGER [dbo].[em_upd_self_serv_t]
END
GO
CREATE TRIGGER [dbo].[em_upd_self_serv_t]
ON [dbo].[em]
AFTER UPDATE
AS
BEGIN
DECLARE @em_id VARCHAR(35),
@em_loc_cnt INT;
SET @em_id = (SELECT em_id FROM inserted);
SET @em_loc_cnt = (SELECT COUNT(*) FROM emlocs WHERE em_id = @em_id);
IF (@em_loc_cnt = 0)
BEGIN
-- I want to set the fl_id and the rm_id to NULL
END
END;
Upvotes: 1
Views: 46
Reputation: 754368
Your fundamental flaw is that you seem to expect the trigger to be fired once per row - this is NOT the case in SQL Server. Instead, the trigger fires once per statement, and the pseudo table Inserted
might contain multiple rows.
Given that that table might contain multiple rows - which one do you expect will be selected here??
SET @em_id = (SELECT em_id FROM inserted);
It's undefined - you might get the values from arbitrary rows in Inserted
.
You need to rewrite your entire trigger with the knowledge the Inserted
WILL contain multiple rows! You need to work with set-based operations - don't expect just a single row in Inserted
!
You need to change your code to something like this:
IF EXISTS (SELECT * FROM sys.triggers WHERE [name] = 'em_upd_self_serv_t')
DROP TRIGGER [dbo].[em_upd_self_serv_t]
GO
CREATE TRIGGER [dbo].[em_upd_self_serv_t]
ON [dbo].[em]
AFTER UPDATE
AS
UPDATE dbo.em
SET fl_id = NULL, rm_id = NULL
FROM Inserted i
WHERE em_id = i.em_id
AND NOT EXISTS (SELECT * FROM dbo.emlocs WHERE em_id = i.em_id)
Upvotes: 2