如果删除带有外键的行,如何在表中留一行外键值?

时间:2018-04-25 13:05:15

标签: postgresql

有table1:

CREATE TABLE table1
(
  id serial NOT NULL,
  CONSTRAINT pk_table1_id PRIMARY KEY (id),
)

有table2:

CREATE TABLE table2
(
  id serial NOT NULL,
  fk_1 integer,
  CONSTRAINT fk_to_table1 FOREIGN KEY (fk_1)
      REFERENCES table1 (id) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE NO ACTION
      NOT VALID
)

当我尝试从table1删除某些行时,我得到了异常:

UPDATE or DELETE in the table "table1" violates the foreign key constraint "fk_to_table1" of the table "table2"

如果删除了table1中带有外键的行,是否有某种方法可以在table2中保留(保存)一行,其中fk_1(来自table1的id)的值相同?

实施例: 表1:

id
1
2
3

Teble2:

id fk_1
1 | 1
2 | 1
3 | 3
4 | 2

从table1删除第一行后我想看到的内容:

表1:

id
2
3

Teble2:

id fk_1
1 | 1
2 | 1
3 | 3
4 | 2

2 个答案:

答案 0 :(得分:0)

您可以使用ON DELETE SET NULL

执行此操作
CREATE TABLE table2
(
  id int NOT NULL,
  fk_1 integer,
  CONSTRAINT fk_to_table1 FOREIGN KEY (fk_1)
      REFERENCES table1 (id)
      ON UPDATE CASCADE 
      ON DELETE SET NULL
);

insert into table1 values (1), (2);
insert into table2 values (1,1), (2,1), (3,2), (4,2);

然后如果你跑:

delete from table1
where id = 1;

表2将如下所示:

id | fk_1
---+-----
 1 |     
 2 |     
 3 |    2
 4 |    2

在线示例:http://rextester.com/NPUG18060

答案 1 :(得分:0)

简短的回答是:你做不到。

外键的目的是验证当该属性具有值时,该值在引用的表中(除非值为NULL时---表中不需要存在NULL)。

两个建议:

解决方案1.将元组保留在表2中,不要删除它。相反,添加一个布尔属性,确定元组是否已被删除。

专门针对您的问题。添加删除到表的属性。 将if设置为false。并且当元组被删除时 创建一个触发器,将此属性设置为true。这很麻烦 并且容易出错。

解决方案2(这是我首选的解决方案)。您可以使用通过触发器管理的第三个表。 每次添加table2中的元组时,table3的元组都是 添加。表3只有一个属性(您想拥有的属性) 引用的外键)。 Table3将是属于Table2的属性的所有值的集合。添加到Table3的触发器应该使用upsert,以防之前已经看到添加的属性。 然后,Table1将使用指向Table3的外键约束。