30

我有两张桌子:

TableY:
    id, name, description

TableX:
    id, name, y_id

我在TableX( y_id REFERENCING tableY id ON DELETE CASCADE) 中添加了一个外键。当我从中删除时TableXTableY id剩余部分(虽然理论上应该删除)。我想我误解了该ON DELETE CASCADE选项的工作原理。谁能告诉我做错了什么?

我在DELETE CASCADE上也看到了这个,但对我来说没有多大意义。

4

2 回答 2

61

简短的回答

ON DELETE CASCADE 指定约束选项。在您的情况下(假设您有依赖于 table_x 的 table_x 和 table_y)当您删除 table_x 中的行并且从 table_y 引用该行时,table_x 中的行将被删除,并且在 table_y 中引用该行的所有行也将被删除。

当您要删除表并在此表上依赖一个或多个其他表时,请使用 DROP TABLE 和 CASCADE 关键字。

有关 DROP、DELETE 和 ON DELETE CASCADE 约束选项的更多信息

删除与删除

当您想从数据库中删除表时,请使用 word drop。当您使用单词 delete 时,表示您要从表中删除/删除内容(但希望表保持 = 继续存在于数据库中)。

删除从其他表引用的行

当您在表中有行(例如 table_x 和 id 为 1 的行)并且该行被其他表引用(在其他表中有与该条目链接的外键)时,您无法删除该行,如下所示。你会得到一个错误。

DELETE FROM table_x WHERE id = 1;

ERROR:  update or delete on table "table_x" violates foreign key constraint "constraint_name" on table "table_y"
DETAIL:  Key (id)=(1) is still referenced from table "table_y".

原因在错误的详细部分中描述。其他表/表中的条目/条目引用此条目。例如,您可以想象表 account 和表 account_activity。当您从表帐户中删除条目(删除一个帐户)时,您应该从表 account_activity 中删除所有引用表帐户中此特定条目的条目。如果不是,您最终会得到不涉及任何帐户的帐户活动。

根据您想要实现的目标,有两种可能性:

  1. 您要删除整个表 (table_x) 的内容和所有对该表有引用(外键)的表的内容。
  2. 您想从一个表中删除 WHERE 子句中指定的一个或多个条目(行),并删除所有引用此条目的行(如上面提到的 account 和 account_activity 的示例)。

1) 使用带有 CASCADE 关键字的 TRUNCATE

TRUNCATE table_x CASCADE;

2) 更改您在 table_y 中对列的约束,使其具有 ON DELETE CASCADE 选项。

ALTER TABLE table_y   
    DROP CONSTRAINT constraint_name,   
    ADD CONSTRAINT constraint_name FOREIGN KEY (column_in_table_y)
          REFERENCES table_x (referenced_column_in_table_x) ON DELETE CASCADE;

删除其他表所依赖的表

当您有表(例如 table_x)并且其他表/表依赖于它时,您不能删除此表。依赖意味着其他表引用(具有外键)此表(table_x)。当您尝试删除此类表时,您会收到错误。

DROP TABLE table_x;

ERROR:  cannot drop table table_x because other objects depend on it
DETAIL:  constraint id_x_fk on table table_y depends on table table_x
HINT:  Use DROP ... CASCADE to drop the dependent objects too.

该错误给出提示。当您想要删除这样的表时,您必须使用带有级联关键字的 drop。该表将被删除,并且所有引用该表的约束也将被删除。

DROP TABLE table_x CASCADE;

例子

创建 table_x 和 table_y。

CREATE TABLE table_x
(
  id integer NOT NULL,
  text character varying(255) NOT NULL,
  CONSTRAINT table_x_pk PRIMARY KEY (id)
);

CREATE TABLE table_y
(
  id integer NOT NULL,
  text character varying(255) NOT NULL,
  id_x integer NOT NULL,
  CONSTRAINT table_y_pk PRIMARY KEY (id)
);

在 table_y 的列 id_x 上创建名称为 id_x_fk 的约束。

ALTER TABLE table_y
  ADD CONSTRAINT id_x_fk FOREIGN KEY (id_x)
      REFERENCES table_x (id);

将测试数据插入 table_x 和 table_y。

INSERT INTO table_x VALUES
    (1, 'super x'),
    (2, 'great x');

INSERT INTO table_y VALUES
    (1, 'y one', 2),
    (2, 'y two', 1),
    (3, 'y three', 1);

从 table_x 中删除(错误)。

DELETE FROM table_x WHERE id = 1;

删除和添加具有相同名称的约束。

ALTER TABLE table_y
  DROP CONSTRAINT id_x_fk,
  ADD CONSTRAINT id_x_fk FOREIGN KEY (id_x)
      REFERENCES table_x (id) ON DELETE CASCADE;

从 table_x 和 table_y 中删除(正确)。

DELETE FROM table_x WHERE id = 1;

删除 table_x 和 table_y 中的所有内容。

TRUNCATE table_x CASCADE;

删除(删除)table_x 并删除 table_y 中的 id_x_fk 约束。

DROP TABLE table_x CASCADE;

注意

如果您在 table_x 中有行(例如,id = 3)并且此条目(此 id)未从 table_y 引用,您可以删除该行,即使约束没有 ON DELETE CASCADE 选项(因为没有违反约束)。

该代码在“PostgreSQL 9.2.4,由 Visual C++ build 1600, 64-bit 编译”上进行了测试。

资料来源:

http://www.postgresql.org/docs/current/static/sql-droptable.html

http://www.postgresql.org/docs/current/static/sql-delete.html

http://www.postgresql.org/docs/current/static/ddl-constraints.html

http://www.postgresql.org/docs/current/static/sql-altertable.html

PostgreSQL 删除所有内容

于 2014-08-26T06:48:07.823 回答
17

估计你误会了 尝试删除行TableY,相应的行将TableX被级联删除。当您有辅助相关表并希望通过从主表中删除父行来清除它们而不违反约束或留下垃圾时,此选项是必不可少的。

于 2012-07-16T12:57:48.917 回答