SQL触发器无法正常工作

时间:2010-09-16 14:41:33

标签: sql sql-server sql-server-2005 data-integrity

这是我拥有的2个表,我想实现一个触发器,客户不能拥有一个银行超过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 个答案:

答案 0 :(得分:3)

这很容易用约束来实现:

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%保证数据的完整性。

要插入,我会使用Numbers表:

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 :(得分:1)

我会尝试这样的事情:

更换触发器的这一部分

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表中可能有多个记录。如果这些记录针对多个客户,并且任何客户导致此触发器回滚事务,则不会应用那些未违反规则的客户的更新。这可能永远不会发生(如果您的应用程序永远不会一次更新多个客户的记录),或者可能是预期的行为。

答案 2 :(得分:0)

尝试使用此代替触发器中的当前查询。我认为这可能有用。

我的语法可能有点偏,但你会得到一般的想法。

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) 

答案 3 :(得分:0)

您查询的问题在于您只按唯一客户标识符进行搜索。

您的查询必须一起搜索唯一客户和银行标识符的计数。我会将确切的查询留给您,但这是您想要的伪代码:

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

这将返回客户+银行组合存在的次数。这是你想要的限制。

答案 4 :(得分:0)

感谢您的答案,经过一切,我想出了这个解决方案。我插入了一个嵌套查询,它将为我提供银行代码,并通过该代码获取计数

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