MS SQL触发器实现数据完整性约束的正确性及优化咨询
问题1:抽象实体子表的唯一性校验
表结构
CREATE TABLE a ( id int NOT NULL PRIMARY KEY, date datetime NOT NULL, client_id int NOT NULL -- 关联clients表 -- 实体a的其他属性 );
表a为抽象实体,实际存在8张子表定义具体类型,示例如下:
CREATE TABLE b ( id int NOT NULL PRIMARY FOREIGN KEY REFERENCES a (id) -- 实体b的其他属性 ); CREATE TABLE c ( id int NOT NULL PRIMARY FOREIGN KEY REFERENCES a (id) -- 实体c的其他属性 );
需求与现有实现
需求为:同一客户每日只能拥有一条b类型或c类型记录(可同时拥有b和c)。由于属性分属不同表,无法使用UNIQUE约束,我采用触发器实现各子类型的唯一性校验:
CREATE TRIGGER trigger_b_upsert ON b AFTER INSERT, UPDATE AS IF EXISTS ( SELECT 1 FROM a a JOIN b b ON a.id = b.id WHERE a.client_id IN ( SELECT client_id FROM a a JOIN inserted i ON a.id = i.id ) AND date IN ( SELECT date FROM a a JOIN inserted i ON a.id = i.id ) GROUP BY date, client_id HAVING count(*) > 1 ) BEGIN RAISERROR ('not allowed.', 10, 1) ROLLBACK TRANSACTION END
c表使用相同逻辑的触发器。
测试案例
案例1:同一客户同日插入两条b类型记录(应触发错误)
INSERT INTO a (id, date, client_id) VALUES (1, '2050-01-01', 1); INSERT INTO b (id) VALUES (1); INSERT INTO a (id, date, client_id) VALUES (2, '2050-01-01', 1); INSERT INTO b (id) VALUES (2); -- 应抛出错误
案例2:同一客户同日插入b和c类型记录(应允许)
INSERT INTO a (id, date, client_id) VALUES (1, '2050-01-01', 1); INSERT INTO b (id) VALUES (1); INSERT INTO a (id, date, client_id) VALUES (2, '2050-01-01', 1); INSERT INTO c (id) VALUES (2); -- 应执行成功
案例3:同一客户不同日期插入多条同类型记录(应允许)
INSERT INTO a (id, date, client_id) VALUES (1, '2050-01-01', 1); INSERT INTO a (id, date, client_id) VALUES (2, '2050-01-02', 1); INSERT INTO a (id, date, client_id) VALUES (3, '2050-01-01', 1); INSERT INTO a (id, date, client_id) VALUES (4, '2050-01-02', 1); INSERT INTO b (id) VALUES (1); INSERT INTO b (id) VALUES (2); -- 应执行成功 INSERT INTO c (id) VALUES (3); INSERT INTO c (id) VALUES (4); -- 应执行成功
疑问
由于我对MS SQL并不熟悉,想请教该方案是否正确,是否存在性能问题及优化方向。
问题2:关联表的client_id一致性校验
补充表结构
-- 另一张关联客户的表,与a无关 CREATE TABLE e ( id int NOT NULL PRIMARY KEY, client_id int NOT NULL -- 关联clients表 -- 实体e的其他属性 ); CREATE TABLE d ( id int NOT NULL PRIMARY FOREIGN KEY REFERENCES a (id), e_id int NOT NULL PRIMARY FOREIGN KEY REFERENCES e (id) -- 实体d的其他属性 );
需求与现有实现
当前结构允许插入a、d关联e的记录,但a.client_id与e.client_id可能不一致,该场景需禁止。我编写了如下触发器:
CREATE TRIGGER trigger_d_upsert ON d AFTER INSERT, UPDATE AS IF EXISTS ( SELECT 1 FROM a a JOIN inserted i ON a.id = i.id JOIN e e on e.id = i.e_id WHERE e.client_id != a.client_id ) BEGIN RAISERROR ('Conflict client_id.', 10, 1) ROLLBACK TRANSACTION END
疑问
请问是否有更优的解决方案?
内容的提问来源于stack exchange,提问作者Emaborsa
相关产品推荐
相关产品推荐

