使用空值为另一个表中的值创建检查约束

时间:2012-08-30 15:59:06

标签: sql sql-server-2000 referential-integrity

我有两个表,A和B.结构如下:

CREATE TABLE A (
    w int NOT NULL,
    x int NOT NULL,
    y int NOT NULL,
    CONSTRAINT PK_A PRIMARY KEY (w, x, y)
)

CREATE TABLE B (
    w int NOT NULL,
    y int NULL,
    z int NOT NULL
)

我想确保在表B中输入的任何值集合,w和y在表A中。如果表B中的y值为null,我只想确保w在表A中。

一些示例数据,插入和预期结果:

Table A
w  x  y
----------
1  1  1
1  1  2
1  2  1
1  3  2
2  1  1

INSERT INTO B (w, y, z) VALUES (1, 1, 3) -- good
INSERT INTO B (w, y, z) VALUES (1, NULL, 3) -- good
INSERT INTO B (w, y, z) VALUES (1, 1, 4) -- good
INSERT INTO B (w, y, z) VALUES (2, NULL, 3) -- good
INSERT INTO B (w, y, z) VALUES (1, 3, 1) -- fail
INSERT INTO B (w, y, z) VALUES (3, NULL, 1) -- fail

这有什么办法吗?我正在使用SQL Server 2000,如果它发挥作用。

1 个答案:

答案 0 :(得分:2)

很遗憾,您无法在B.wB.y上使用外键约束,因为它们会引用A上的非唯一列。但您可以通过触发器添加此检查:

create trigger check_w on B for insert, update
as
if not exists(select * from A join inserted on A.w = inserted.w) 
begin
  raiserror('W not in A!', 1, 1)
  rollback transaction
end

GO

create trigger check_y on B for insert, update
as
if 
(select y from inserted) is not null and 
not exists(select * from A join inserted on A.y = inserted.y) 
begin
  raiserror('Y not null and not in A!', 1, 1)
  rollback transaction
end

GO

你绝对可以将这两个触发器合二为一。

另请注意,对于delete操作,您需要A上的触发器。如果B上存在匹配的行,或者您执行级联删除操作,则可以阻止删除。