SQL Trigger не работает правильно - PullRequest
2 голосов
/ 16 сентября 2010

вот две таблицы, которые у меня есть, я хочу реализовать триггер, который клиент не может иметь более 5 счетов из одного банка, но может иметь более 5 в общей сложности .

  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),
   );

Вот триггер, который я написал, но я не могу создать более 5 учетных записей, потому что он проверяет все счета во всех банках, а не в одном банке.

    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

ПРОБЛЕМА НАХОДИТСЯ В ФУНКЦИИ GROUPBY, КАК Я Угадаю.

Ответы [ 5 ]

3 голосов
/ 16 сентября 2010

это легко реализовать с помощью ограничений:

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),
   );

Редактировать: иногда триггеры не срабатывают.Только надежные ограничения 100% гарантируют целостность данных.

Чтобы вставить, я бы использовал таблицу чисел:

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)

Я бы использовал триггер, чтобы запретить изменения BANK_CODE.

1 голос
/ 16 сентября 2010

Я бы попробовал что-то вроде этого:

Замените эту часть вашего триггера

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

на:

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

Также учтите, что таблица INSERTED можетесть несколько записей в нем.Если эти записи относятся более чем к одному клиенту, и любой из клиентов заставляет этот триггер откатить транзакцию, то обновления для тех клиентов, которые не нарушали ваше правило, не будут применяться.Это может никогда не произойти (если ваше приложение никогда не обновляет записи для более чем одного клиента за раз), или может быть предполагаемым поведением.

0 голосов
/ 17 сентября 2010

Спасибо за ответы, пройдя все, я придумал это решение. Я вставил вложенный запрос, который даст мне код банка, и по этому коду я получу счет

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
0 голосов
/ 16 сентября 2010

Проблема с вашим запросом в том, что вы ищете только по уникальному идентификатору клиента.

Ваш запрос должен искать количество уникальных идентификаторов клиента И банка вместе.Я оставлю вам точный запрос, но вот что вы хотите в псевдокоде:

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

Это вернет, сколько раз существовала комбинация клиент + банк.Это предел, который вы хотите.

0 голосов
/ 16 сентября 2010

Попробуйте вместо текущего запроса в вашем триггере. Я думаю, что это может сработать.

Мой синтаксис может быть немного неправильным, но вы получите общее представление.

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) 
...