简体   繁体   English

PostgreSQL:外键/删除级联

[英]PostgreSQL: FOREIGN KEY/ON DELETE CASCADE

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?所以逻辑很简单,在用户删除类别 x 下的所有书后,x 从猫中删除,我尝试了上面的方法但不起作用,在我清理表书后,表类别仍然填充,这是怎么回事?

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.您以相反的方式说,这并不是说当您从子表中删除时,记录将从父表中删除。

UPDATE 1:

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. ON DELETE CASCADE选项用于指定在父表中删除相应行时是否要删除子表中的行。 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. cascading-deletes 功能的主要优点是它允许您减少执行删除操作所需的 SQL 语句的数量。

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.因此,在您的情况下,当用户从categories表中删除条目时,行将从书籍表中删除。 :) :)

Hope this helps you :)希望这可以帮助你:)

Excerpt from PostgreSQL documentation : PostgreSQL 文档摘录

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. [...] CASCADE指定当引用的行被删除时,引用它的行也应该被自动删除。

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 .这意味着如果您删除schemas.books中由schemas.category中的category_id引用的行,任何此类引用行也将被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 . DELETE FROM CASCADE将通过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!如果你真的需要相反的(由数据库检查),你将不得不写一个触发器!

In my humble experience with postgres 9.6, cascade delete doesn't work in practice for tables that grow above a trivial size.根据我对 postgres 9.6 的简陋经验,级联删除在实践中对于增长超过微不足道大小的表不起作用。

  • Even worse, while the delete cascade is going on, the tables involved are locked so those tables (and potentially your whole database) is unusable.更糟糕的是,当删除级联进行时,所涉及的表被锁定,因此这些表(可能还有您的整个数据库)无法使用。
  • Still worse, it's hard to get postgres to tell you what it's doing during the delete cascade.更糟糕的是,很难让 postgres 告诉你它在删除级联期间做了什么。 If it's taking a long time, which table or tables is making it slow?如果需要很长时间,哪个或哪些表使它变慢? Perhaps it's somewhere in the pg_stats information?也许它在 pg_stats 信息中的某个地方? It's hard to tell.很难说。

PostgreSQL Forging Key DELETE, UPDATE CASCADE 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
);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM