SQL触发器工作不正常
下面是我的两个表,我想实现一个触发器,客户在一家银行的账户不能超过5个,但总共可以超过5个SQL触发器工作不正常,sql,sql-server,sql-server-2005,data-integrity,Sql,Sql Server,Sql Server 2005,Data Integrity,下面是我的两个表,我想实现一个触发器,客户在一家银行的账户不能超过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
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函数中。试试这个,而不是触发器中的当前查询。我想这可能行得通 我的语法可能有点不对劲,但你能大致了解我的意思
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)
查询的问题在于,您只按唯一的客户标识符进行搜索 您的查询必须同时搜索唯一客户和银行标识符的计数。我将把确切的查询留给您,但以下是您想要的伪代码:
SELECT COUNT(customer_id)
FROM table_name
WHERE customer_id = customer_id_to_validate
AND bank_id = bank_id_to_validate
这将返回客户+银行组合存在的次数。这就是您想要的限制。这很容易通过约束实现:
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)
我会使用触发器来禁止修改银行代码。我会尝试以下方法: 更换触发器的这一部分
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
还考虑插入表中可能有多条记录。如果这些记录针对多个客户,并且任何客户导致此触发器回滚事务,则不会应用未违反规则的客户的更新。这可能永远不会发生(如果您的应用程序一次从不更新多个客户的记录),或者可能是预期的行为
谢谢你的回答,在经历了这一切之后,我想出了这个解决方案。我插入了一个嵌套查询,它将给我银行代码,然后通过该代码我得到了计数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
如果您发布代码或XML,请在文本编辑器中突出显示这些行,并单击编辑器工具栏上的“代码”按钮(101 010),以很好地格式化和语法突出显示它!您是否会通过将数字作为触发器的一部分进行计算来维护银行的数字?您是否还必须保护自己不被直接更新到银行的账户号码(例如,更新账户号码?银行的客户设置号码=1)?这似乎比OP目前的方法更复杂。没有必要“保护自己不受直接更新银行编号的影响”,因为有一些限制,你最终不能得到脏数据。该列中可以有空白,但不能有重复项。是的,@AlexKuznetsov,请详细说明您的方法。我不知道插入的表中可以有多条记录