PostgreSQL:FOREIGN KEY / ON DELETE CASCADE

时间:2013-01-03 14:55:04

标签: sql postgresql cascade

我有两张桌子在这里:

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)
);

所以逻辑很简单,用户删除了类别x下​​的所有书籍后,x从猫中删除,我尝试了上面的方法但是不起作用,在我清理了表格书之后,表格类别仍然填充,出了什么问题?

4 个答案:

答案 0 :(得分:63)

具有级联删除的外键意味着如果删除父表中的记录,则将自动删除子表中的相应记录。这称为级联删除。

您反过来说,这不是从子表中删除时,记录将从父表中删除。

UPDATE 1:

ON DELETE CASCADE选项用于指定在父表中删除相应行时是否要在子表中删除行。如果未指定级联删除,则数据库服务器的默认行为会阻止您删除表中的数据(如果其他表引用它)。

如果指定此选项,稍后在删除父表中的行时,数据库服务器还会删除子表中与该行(外键)关联的所有行。级联删除功能的主要优点是它允许您减少执行删除操作所需的SQL语句数量。

所以当你从父表中删除行而不是从子表中删除行时会发生什么。

因此,在用户从CAT表中删除条目的情况下,将从books表中删除行。 :)

希望这可以帮助你:)

答案 1 :(得分:18)

来自PostgreSQL documentation

Exerpt

  

限制和级联删除是两种最常见的选项。 [...] CASCADE指定当删除引用的行时,也应自动删除引用它的行。

这意味着,如果您删除书籍引用的类别,则ON DELETE CASCADE也会删除引用书籍。

示例

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部族将CASCADE REFERENCESsauron@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) 为单位。

def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:firstname, :secondname, :email, :password, :password_confirmation, :remember_me) }
    devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:login, :email, :password, :remember_me) }
    devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:firstname, :secondname ,:email, :password, :password_confirmation, :current_password) }
end

如果你真的需要相反的(由数据库检查),你将不得不写一个触发器!

答案 2 :(得分:0)

在我使用postgres 9.6的简单经验中,级联删除在实践中对于增长超过平凡大小的表格不起作用。

  • 更糟糕的是,当删除级联正在进行时,所涉及的表格 被锁定所以那些表(可能是你的整个数据库) 无法使用。
  • 更糟糕的是,很难让postgres告诉你什么 它正在删除级联中执行。如果需要很长时间, 哪一张桌子让它变慢?也许它就在某个地方 pg_stats信息?这很难说。

答案 3 :(得分:-6)

  

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
);