T-SQL - Insert trigger; IF EXISTS not evaluating as intended


T-SQL - Insert trigger; IF EXISTS not evaluating as intended



Not sure what I'm missing. When I debug and step through the INSERT query I've included below, I see that '%a%' is the value of @Answer, and 103 is the value for @ItemId.


INSERT


'%a%'


@Answer


@ItemId



IF EXISTS is always evaluating to false when I insert the values shown beneath:


IF EXISTS


CREATE TRIGGER TR_cc_Additional_Information_Answers_INS
ON cc_Additional_Information_Answers
AFTER INSERT
AS
BEGIN
CREATE TABLE temp_answers
(
TempAnswer VARCHAR(50),
TempAdditional_Information_ItemID INT
)

INSERT INTO temp_answers (TempAnswer, TempAdditional_Information_ItemID)
SELECT Description, Additional_Information_ItemID
FROM inserted

DECLARE @Answer varchar(50)
SELECT @Answer = '''%' + t.TempAnswer + '%''' FROM temp_answers t

DECLARE @ItemId int
SELECT @ItemId = t.TempAdditional_Information_ItemID FROM temp_answers t

IF EXISTS(SELECT 1
FROM cc_Additional_Information_Answers a
WHERE a.Description LIKE @Answer
AND a.Additional_Information_ItemID = @ItemId)
BEGIN
RAISERROR('Answer is too similar to pre-existing answers for this item', 16, 1)
ROLLBACK TRANSACTION
RETURN
END

DROP TABLE temp_answers
END
GO



And this is my insert query:


INSERT INTO cc_Additional_Information_Answers (Additional_Information_ItemID, Description)
VALUES (103, 'a')



And the pre-existing record:



existing record



Thanks in advance, SQL community!



EDIT: this also does not behave as expected. . .


INSERT INTO cc_Additional_Information_Answers (Additional_Information_ItemID, Description)
VALUES (103, 'a')



Given this data



enter image description here





Your trigger has a MAJOR logical flaw. It assumes there will only ever be a single row in the inserted table. This is not how triggers work in sql server, they fire once per operation. Also, using persistent tables as temp tables is very problematic. You have created a race condition here that is not needed. Simply join to inserted any time you need it throughout your trigger.
– Sean Lange
Jul 2 at 20:51





I would also be very cautious of issuing a rollback in a trigger. If your calling code has a transaction it will likely crash because the transaction won't be available anymore to rollback from the application.
– Sean Lange
Jul 2 at 20:52





@SeanLange thanks for your feedback; I’ll work in your suggestions. I don’t see how they’ll solve the issue I’ve described though.
– Steve Boniface
Jul 2 at 21:37





@SeanLange I can say with certainty that only one record will be inserted per transaction. We are not doing batch inserts
– Steve Boniface
Jul 2 at 21:46





The answer could be '%' + t.TempAnswer + '%' FROM temp_answers t (without the extra quotes)…
– WolfgangK
Jul 2 at 22:05





1 Answer
1



Your IF EXISTS will always evaluate to true because the inserted value is already inserted (although it can be rolled back) when the trigger runs (it's an "AFTER" trigger).
So you will want to inspect only those records that existed in the table before the insertion. I always use an outer join for this. Also: I would never create a table in a trigger. The following should work as expected:


CREATE TRIGGER TR_cc_Additional_Information_Answers_INS ON cc_Additional_Information_Answers
AFTER INSERT
AS
BEGIN

IF EXISTS(
SELECT 1 FROM cc_Additional_Information_Answers a
LEFT OUTER JOIN inserted i ON a.Additional_Information_AnswerID = i.Additional_Information_AnswerID
INNER JOIN inserted temp ON a.Additional_Information_ItemID = temp.Additional_Information_ItemID
WHERE a.Description LIKE '%' + temp.Description + '%'
AND i.Additional_Information_AnswerID IS NULL
)
BEGIN
RAISERROR('Answer is too similar to pre-existing answers for this item', 16, 1)
ROLLBACK TRANSACTION
RETURN
END
END
GO





Thanks for sharing. With the outer join, is the logic to check for answerID = null due to the fact that the answer ID will be inserted by the DB after the insert query has run?
– Steve Boniface
Jul 2 at 22:18





@SteveBoniface Yes, the intention of outer join and "is null" is to make sure to only compare to those records that are not currently being inserted.
– WolfgangK
Jul 2 at 22:22





I think this is precisely what I need. Will give it a shot and will confirm. Thank you!
– Steve Boniface
Jul 2 at 22:28





I don’t understand why Rollback transaction works if the insert has already been executed though. That part doesn’t make sense to me. Doesn’t the insert have to be committed to the DB to get an identity value assigned to that record?
– Steve Boniface
Jul 2 at 22:35





@SteveBoniface From outside the transaction, this would be considered a "dirty read", but from inside, we of course must be able to see our own changes. And for the ID... yes, that's where "gaps" in the identity columns can come from.
– WolfgangK
Jul 2 at 22:43






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

api-platform.com Unable to generate an IRI for the item of type

How to set up datasource with Spring for HikariCP?

Display dokan vendor name on Woocommerce single product pages