Suppose we have a 1 to N (cardinality) relationship between entities A and B which are represented in our relational model through two tables: the a table with an id attribute, its primary key, and the b one with an id attribute, its primary key, and another one, a_id, the foreign key which links to a:
CREATE TABLE a (
id INTEGER,
CONSTRAINT a_primary_key (id)
);
CREATE TABLE b (
id INTEGER,
a_id INTEGER,
CONTRAINT b_primary_key (id),
CONTRAINT b_foreign_key (a_id) REFERENCES a(id)
);
The question is, how can we enforce full participation of this relationship? That is, how can we guarantee that all tuples of both tables are all linked or, what is the same, how can we avoid to have unlinked tuples?
For b table the solution is easy. We must include an a_id (the foreign key) when we insert a tuple, so we are always relating b tuples to a. If we want to delete all associated tuples of b when removing the corresponding a, we can add ON DELETE CASCADE to the b_foreign_key constraint and that's all. But the a side is more difficult.
First, we must guarantee that a tuple in a is inserted if and only if we are sure a corresponding one in table b is created also. To do this, we must use a transaction which do both insertions or none of them.
And second, how can we enforce that when we remove all tuples of b related with one of a, the latter became removed? One solution to guarantee this in PostgreSQL is to build a PL/pgSQL trigger which checks, each time an update or delete occurs in b, if there are tuples in b related with a which include the same a_id of the b tuple currently being removed, and delete the corresponding a tuple if this occurs:
CREATE OR REPLACE FUNCTION enforce_a_participation() RETURNS trigger AS $$
BEGIN
PERFORM a_id FROM b WHERE a_id=OLD.a_id;
IF NOT FOUND THEN
DELETE FROM a WHERE id=OLD.a_id;
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER enforce_a_participation_trigger AFTER DELETE OR UPDATE
ON b FOR EACH ROW EXECUTE PROCEDURE enforce_a_participation();
(remember to write CREATE PROCEDURAL LANGUAGE plpgsql; before creating your first PL/pgSQL function)
This way, when the last row of b related with one row of a is removed, the corresponding a is deleted also, and the problem become solved.
0 comments:
Post a Comment