Reputation: 2329
I have two tables like here:
DROP TABLE IF EXISTS schemas.book;
DROP TABLE IF EXISTS schemas.category;
DROP SCHEMA IF EXISTS schemas;
CREATE SCHEMA schemas;
CREATE TABLE schemas.category (
id BIGSERIAL PRIMARY KEY,
name VARCHAR NOT NULL,
UNIQUE(name)
);
CREATE TABLE schemas.book (
id BIGSERIAL PRIMARY KEY,
published DATE NOT NULL,
category_id BIGINT NOT NULL REFERENCES schemas.category
ON DELETE CASCADE
ON UPDATE CASCADE,
author VARCHAR NOT NULL,
name VARCHAR NOT NULL,
UNIQUE(published, author, name),
FOREIGN KEY(category_id) REFERENCES schemas.category (id)
);
So the logic is simple, after user removes all book under category x, x gets removed from cats, i tried method above but doesn't work, after i clean table book, table category still populated, what's wrong?
Upvotes: 98
Views: 230479
Reputation: 10073
A foreign key with a cascade delete means that if a record in the parent table is deleted, then the corresponding records in the child table will automatically be deleted. This is called a cascade delete.
You are saying in a opposite way, this is not that when you delete from child table then records will be deleted from parent table.
ON DELETE CASCADE option is to specify whether you want rows deleted in a child table when corresponding rows are deleted in the parent table. If you do not specify cascading deletes, the default behaviour of the database server prevents you from deleting data in a table if other tables reference it.
If you specify this option, later when you delete a row in the parent table, the database server also deletes any rows associated with that row (foreign keys) in a child table. The principal advantage to the cascading-deletes feature is that it allows you to reduce the quantity of SQL statements you need to perform delete actions.
So it's all about what will happen when you delete rows from Parent table not from child table.
So in your case when user removes entries from categories
table then rows will be deleted from books table.
Upvotes: 133
Reputation: 2552
Excerpt from PostgreSQL documentation:
Restricting and cascading deletes are the two most common options. [...]
CASCADE
specifies that when a referenced row is deleted, row(s) referencing it should be automatically deleted as well.
This means that if you delete a row in schemas.category
, referenced by category_id
in schemas.books
, any such referencing row will also be deleted by ON DELETE CASCADE
.
Example:
CREATE SCHEMA shire;
CREATE TABLE shire.clans (
id serial PRIMARY KEY,
clan varchar
);
CREATE TABLE shire.hobbits (
id serial PRIMARY KEY,
hobbit varchar,
clan_id integer REFERENCES shire.clans (id) ON DELETE CASCADE
);
DELETE FROM
clans will CASCADE
to hobbits by REFERENCES
.
sauron@mordor> psql
sauron=# SELECT * FROM shire.clans;
id | clan
----+------------
1 | Baggins
2 | Gamgi
(2 rows)
sauron=# SELECT * FROM shire.hobbits;
id | hobbit | clan_id
----+----------+---------
1 | Bilbo | 1
2 | Frodo | 1
3 | Samwise | 2
(3 rows)
sauron=# DELETE FROM shire.clans WHERE id = 1 RETURNING *;
id | clan
----+---------
1 | Baggins
(1 row)
DELETE 1
sauron=# SELECT * FROM shire.hobbits;
id | hobbit | clan_id
----+----------+---------
3 | Samwise | 2
(1 row)
If you really need the opposite (checked by the database), you will have to write a trigger!
Upvotes: 115
Reputation: 5
In my humble experience with postgres 9.6, cascade delete doesn't work in practice for tables that grow above a trivial size.
Upvotes: -10
Reputation: 1621
PostgreSQL Forging Key DELETE, UPDATE CASCADE
CREATE TABLE apps_user(
user_id SERIAL PRIMARY KEY,
username character varying(30),
userpass character varying(50),
created_on DATE
);
CREATE TABLE apps_profile(
pro_id SERIAL PRIMARY KEY,
user_id INT4 REFERENCES apps_user(user_id) ON DELETE CASCADE ON UPDATE CASCADE,
firstname VARCHAR(30),
lastname VARCHAR(50),
email VARCHAR UNIQUE,
dob DATE
);
Upvotes: -28