Trigger with a RAISERROR and ELSE case issue
Asked Answered
T

1

8

I am trying to make a bit of code that takes in 2 separate columns, a month and a year. From there I want it to see if those numbers entered have already passed or not. If they have passed, cause an error to pass and stop the transaction. Otherwise, I want it to continue on and insert new information into the table. I know I am close on getting this to work, but I cant seem to get the RAISERROR to fire. I am sure it has to do with the fact I am pretty new at this and I am missing some small detail.

Currently I am taking the two months in as variables and the making a third variable to use to turn the other two into a proper datetime format. Then I use the datediff function to try and see if it has passed that way. To no avail though. I keep getting the insert function going, even if the card date is old.

USE AdventureWorks2012
GO

CREATE TRIGGER BadCreditCardDate
ON Sales.CreditCard
INSTEAD OF INSERT
AS
Begin
DECLARE @ExpMonth tinyint,
        @ExpYear smallint,
        @ExpMonthYear datetime

SELECT  @ExpMonth=ExpMonth, 
        @ExpYear=ExpYear,
        @ExpMonthYear = @ExpYear + '-' + @ExpMonth + '-00' 
FROM INSERTED
    IF
    DATEDIFF(MONTH,@ExpMonthYear,GETDATE()) < 0
    BEGIN
        RAISERROR ('The Credit Card you have entered has expired.' ,10,1)
        ROLLBACK TRANSACTION
    END 

ELSE    
Begin
    INSERT INTO CreditCard (CardType, CardNumber, ExpMonth, ExpYear, ModifiedDate)
    Select CardType, CardNumber, ExpMonth, ExpYear, ModifiedDate FROM inserted
END
End
Trudytrue answered 25/1, 2015 at 18:52 Comment(2)
Your trigger has MAJOR flaw in that you seem to assume it'll be called once per row - that is not the case. The trigger will fire once per statement, so if your UPDATE statements affects 25 rows, you'll get the trigger fired once, but then Inserted and Deleted will each contain 25 rows. Which of those 25 rows will your code select here?? SELECT @ExpMonth = ExpMonth FROM Inserted - it's non-deterministic. You need to rewrite your trigger to take this into account!Pectoralis
You have a hard-coded '00' for the expiration date day. I would expect the DATEDIFF to fail if the expression is not null.Lazor
I
8

I think there is a simpler way to check for expiration:

CREATE TRIGGER BadCreditCardDate
ON Sales.CreditCard
INSTEAD OF INSERT
AS
BEGIN
   IF EXISTS (
      SELECT 1
      FROM inserted
      WHERE (YEAR(GETDATE()) > ExpYear) OR (YEAR(GETDATE()) = ExpYear AND MONTH(GETDATE()) > ExpMonth)
   )
   BEGIN
      RAISERROR ('The Credit Card you have entered has expired.' ,10,1)
      ROLLBACK TRANSACTION
   END 
   ELSE    
      BEGIN
         INSERT INTO CreditCard (CardType, CardNumber, ExpMonth, ExpYear, ModifiedDate)
         SELECT CardType, CardNumber, ExpMonth, ExpYear, ModifiedDate 
         FROM inserted
   END    
END

In this way you effectively check every record to be inserted in CreditCard.

Ingenuity answered 25/1, 2015 at 19:20 Comment(3)
This worked like a charm. I am going to have to look over this bit of code to see how its working and then remember this little beauty.Trudytrue
Won't this rollback the entire transaction (and possible thousands of other possibly valid credit cards from other users if they just so happened to have been on the same transaction?Etymon
@Etymon Yes, it will rollback the entire transaction. It was the OP's intention to place the ROLLBACK inside the trigger. I guess he's not inserting more than one rows per transaction.Ingenuity

© 2022 - 2024 — McMap. All rights reserved.