views:

64

answers:

5

here are the 2 tables i have, i want to implement an trigger that customer cannot have more than 5 accounts from a one bank, but can have more than 5 in total.

  CREATE TABLE ACCOUNT(
   ACCOUNT_NO VARCHAR(20) NOT NULL,
   BALANCE REAL,
   BANK_CODE VARCHAR(20),
   BRANCH_NO VARCHAR(25),
   ACCOUNT_CODE VARCHAR(20),
   PRIMARY KEY(ACCOUNT_NO),
 );

 CREATE TABLE ACCOUNT_CUSTOMER(
   CUS_NO VARCHAR(20) NOT NULL,
   ACCOUNT_NO VARCHAR(20) NOT NULL,

   PRIMARY KEY(CUS_NO,ACCOUNT_NO),
       FOREIGN KEY(ACCOUNT_NO) REFERENCES ACCOUNT(ACCOUNT_NO),
   );

heres the trigger i wrote but i can't create more than 5 accounts in total because it checks for all the accounts in all the banks rather than a single bank.

    CREATE TRIGGER TRIGGER1
    ON ACCOUNT_CUSTOMER 
    FOR INSERT,UPDATE
    AS BEGIN
    DECLARE @COUNT INT
    DECLARE @CUS_NO VARCHAR(20)

    SELECT @COUNT=COUNT(AC.ACCOUNT_NO)
    FROM INSERTED I,ACCOUNT_CUSTOMER AC
    WHERE I.CUS_NO=AC.CUS_NO
    GROUP BY(AC.CUS_NO)

    IF @COUNT>5
    ROLLBACK TRANSACTION
    END

THE PROBLEM IS WITHIN THE GROUPBY FUNCTION AS I GUESS.

A: 

Try this instead of the current query in your trigger. I think that this might work.

My syntax might be a bit off but you get the general idea.

SELECT @COUNT=MAX(COUNT(AC.ACCOUNT_NO))
FROM INSERTED I 
INNER JOIN ACCOUNT_CUSTOMER AC ON I.CUS_NO=AC.CUS_NO 
INNER JOIN ACCOUNT A ON AC.ACCOUNT_NO = A.ACCOUNT_NO
GROUP BY(AC.CUS_NO, A.BANK_CODE) 
InSane
A: 

The trouble with your query is that you are only searching by unique customer identifier.

Your query must search a count of a unique customer AND bank identifier together. I'll leave the exact query to you, but here's what you want in pseudocode:

SELECT COUNT(customer_id)
FROM table_name
WHERE customer_id = customer_id_to_validate
AND bank_id = bank_id_to_validate

This will return how many times a customer + bank combination exist. That's the limit you want.

bobwaycott
If you post code or XML, **please** highlight those lines in the text editor and click on the "code" button (101 010) on the editor toolbar to nicely format and syntax highlight it!
marc_s
My bad. Thanks for the edit.
bobwaycott
+3  A: 

this is easy to implement with constraints:

CREATE TABLE ACCOUNT(
   ACCOUNT_NO VARCHAR(20) NOT NULL,
   BALANCE REAL,
   BANK_CODE VARCHAR(20),
   BRANCH_NO VARCHAR(25),
   ACCOUNT_CODE VARCHAR(20),
   PRIMARY KEY(ACCOUNT_NO),
   UNIQUE(ACCOUNT_NO,BANK_CODE)
 );

 CREATE TABLE ACCOUNT_CUSTOMER(
   CUS_NO VARCHAR(20) NOT NULL,
   ACCOUNT_NO VARCHAR(20) NOT NULL,
       BANK_CODE VARCHAR(20),
   NUMBER_FOR_BANK INT NOT NULL CHECK(NUMBER_FOR_BANK BETWEEN 1 AND 5),      
   PRIMARY KEY(CUS_NO,ACCOUNT_NO),
   UNIQUE(CUS_NO,BANK_CODE,NUMBER_FOR_BANK),
       FOREIGN KEY(ACCOUNT_NO, BANK_CODE) REFERENCES ACCOUNT(ACCOUNT_NO, BANK_CODE),
   );

Edit: sometimes triggers do not fire. Only trusted constraints 100% guarantee data integrity.

To insert, I would use Numbers table:

INSERT INTO ACCOUNT_CUSTOMER(
   CUS_NO,
   ACCOUNT_NO,
       BANK_CODE,
   NUMBER_FOR_BANK
   )
SELECT TOP 1    @CUS_NO,
   @ACCOUNT_NO,
       @BANK_CODE,
   NUMBER
FROM dbo.Numbers WHERE NUMBER BETWEEN 1 AND 5
AND NOT EXISTS(SELECT * FROM ACCOUNT_CUSTOMER WHERE CUS_NO=@CUS_NO AND BANK_CODE=@BANK_CODE)

I would use a trigger to prohibit modifications of BANK_CODE.

AlexKuznetsov
Would you maintain NUMBER_FOR_BANK by calculating it as part of the trigger? Would you also have to protect yourself from direct updates to NUMBER_FOR_BANK (e.g. UPDATE ACCOUNT_CUSTOMER SET NUMBER_FOR_BANK = 1)? This seems more complicated then the OP's current approach.
adrift
There is no need to "protect yourself from direct updates to NUMBER_FOR_BANK" - with constraints you cannot end up with dirty data. You can have gaps in that column, but you cannot have duplicates.
AlexKuznetsov
Yes, @AlexKuznetsov, please elaborate on your approach.
Denis Valeev
+1  A: 

I would try something like this:

Replace this part of your trigger

SELECT @COUNT=COUNT(AC.ACCOUNT_NO)
FROM INSERTED I,ACCOUNT_CUSTOMER AC
WHERE I.CUS_NO=AC.CUS_NO
GROUP BY(AC.CUS_NO)

IF @COUNT>5
ROLLBACK TRANSACTION

with this:

IF EXISTS (
        SELECT COUNT(a.ACCOUNT_NO)
        FROM INSERTED i
                JOIN ACCOUNT a ON i.ACCOUNT_NO = a.ACCOUNT_NO
                JOIN ACCOUNT_CUSTOMER c ON i.CUS_NO = c.CUS_NO
        GROUP BY c.CUS_NO, a.BANK_CODE
        HAVING COUNT(a.ACCOUNT_NO) >= 5
    )
    ROLLBACK TRANSACTION

Also consider that the INSERTED table may have multiple records in it. If those records are for more than one customer and any of the customers causes this trigger to rollback the transaction, then the updates for those customers that did not violate your rule will not be applied. This may never happen (if your application never updates records for more than one customer at a time), or may be the intended behavior.

adrift
i didn't knew that inserted table can have multiple records in it
Nipuna Silva
A: 

Thanks for the answers, after going through all, i came up with this solution. I inserted a nested query taht will give me the bankcode and by that code i get the count

CREATE TRIGGER TRIGGER1
ON ACCOUNT_CUSTOMER 
FOR INSERT,UPDATE
AS BEGIN
DECLARE @COUNT INT
DECLARE @CUS_NO VARCHAR(20)

SELECT @COUNT=COUNT(*)
FROM ACCOUNT_CUSTOMER AC, ACCOUNT A
WHERE A.ACCOUNT_NO=AC.ACCOUNT_NO AND A.BANK_CODE=
               (SELECT A.BANK_CODE 
                FROM DIT09C_0293_ACCOUNT A, INSERTED I
                WHERE A.ACCOUNT_NO=I.ACCOUNT_NO
                )
    IF @COUNT>5
        ROLLBACK TRANSACTION
END
Nipuna Silva