Reputation: 841
Let's say I have a PostgreSQL database with tables A, B and C, where A and B have a many-to-many relationship via junction table C. These tables have the following SQL definitions:
CREATE TABLE A
(
id serial NOT NULL,
CONSTRAINT A_pkey PRIMARY KEY (id)
)
CREATE TABLE B
(
id serial NOT NULL,
CONSTRAINT B_pkey PRIMARY KEY (id)
)
CREATE TABLE C
(
A_id integer NOT NULL,
B_id integer NOT NULL,
CONSTRAINT C_pk PRIMARY KEY (A_id, B_id),
CONSTRAINT A_fk FOREIGN KEY (A_id)
REFERENCES A(id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT B_fk FOREIGN KEY (B_id)
REFERENCES B(id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
Now I want to make sure that there is at least one instance of B for each instance of A (in other words: each id in A occurs at least once as A_id in C). Is it possible to check this property using database constraints?
Upvotes: 3
Views: 685
Reputation: 78523
The better approach for your requirement is a constraint trigger.
It should do an exists() check on table C and raise an exception when the required key doesn't exist. (Which, technically, is what the built-in triggers that enforce foreign key constraints basically do.)
It'll go something like:
create function A_C_fkey_check() returns trigger as $$
begin
if not exists (select 1 from C where A_id = new.id) then
raise exception 'invalid key';
end if;
return null;
end;
$$ language plpgsql;
create constraint trigger A_C_fkey_check after insert on A
for each row execute procedure A_C_fkey_check();
That said, I'd suggest that actually enforcing this type of constraint at the database-level isn't a great idea: bizarre edge cases that requires an A without a B invariably show up in my own experience.
Upvotes: 1