Creating a check constraint for values in another table with nulls
-
29-06-2021 - |
Domanda
I have two tables, A and B. The structure looks like this:
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
)
I want to make sure for any set of values entered in table B, that w and y are in table A. If the y value in table B is null, I only want to make sure that w is in table A.
Some sample data, inserts, and expected results:
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
Any way for this to work? I'm using SQL Server 2000 if that comes into play.
Soluzione
Unfortunately, you cannot use a foreign key constraint on B.w
and B.y
because they would reference non-unique columns on A
. But you can add this check via triggers:
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
You can definitely combine these two triggers in one.
Also note that you'll need a trigger on A for the delete
operation. You either prevent deletion if there're matching rows on B, or you perform a cascade delete operation.