On Nov 08, David G. Johnston modulated:
...
> ON DELETE starts with the "one" side of a one-to-many relationship.
> When deleting the one row the question is what should be done with the
> many rows which refer to it. If ALL of the many rows agree to be
> deleted then the one row in question can go away and no error is
> raised. If ANY of the many rows refuse to die then the one row in
> question must remain in order to maintain referential integrity - thus
> an error will be raised.
>
I think I had the same intuition going into this.
However, I am testing with an artificial scenario to focus on the
ordering/precedence behavior. I was even hoping PostgreSQL might raise
an error when I created apparently conflicting constraints, but
unfortunately it does something much more confusing...
You might consider this to explore what happens if someone
accidentally redefines constraints with conflicting actions. I just
redefine the same constraint with only varying constraint name and ON
DELETE clause.
Here, I have assigned constraint names to demonstrate that the rules
are NOT applied based on a lexicographic sort of constraint names but
rather on order of definition (perhaps there is another
internally-generated name that sorts in order of definition?):
======================================
ALTER TABLE refs ADD CONSTRAINT z FOREIGN KEY (t_id) REFERENCES targets (id) ON DELETE NO ACTION;
ALTER TABLE
ALTER TABLE refs ADD CONSTRAINT y FOREIGN KEY (t_id) REFERENCES targets (id) ON DELETE SET NULL;
ALTER TABLE
ALTER TABLE refs ADD CONSTRAINT x FOREIGN KEY (t_id) REFERENCES targets (id) ON DELETE CASCADE;
ALTER TABLE
This test will show that ON DELETE NO ACTION is in effect due to constraint z.
Table "public.refs"
Column | Type | Modifiers
--------+---------+---------------------------------------------------
id | integer | not null default nextval('refs_id_seq'::regclass)
t_id | integer | not null
Indexes:
"refs_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"x" FOREIGN KEY (t_id) REFERENCES targets(id) ON DELETE CASCADE
"y" FOREIGN KEY (t_id) REFERENCES targets(id) ON DELETE SET NULL
"z" FOREIGN KEY (t_id) REFERENCES targets(id)
-------------
Content of refs table before deletion of target:
SELECT * FROM refs;
id | t_id
----+------
1 | 1
2 | 2
3 | 3
(3 rows)
-------------
Attempting to delete a target:
DELETE FROM targets WHERE name = 'foo1' RETURNING *;
ERROR: update or delete on table "targets" violates foreign key constraint "z" on table "refs"
DETAIL: Key (id)=(2) is still referenced from table "refs".
The attached BASH script will perform a sequence of tests defining the
constraints in different orders and showing the results. The excerpt
above is from the first test scenario.
It accepts optional arguments which are passed to 'psql' and can run
with no arguments if you can talk to your default DB with 'psql'
absent of any arguments, i.e. with Unix domain socket authentication.
It only creates and destroys tables public.targets and public.refs...
Thanks,
Karl