【问题标题】:MSSQL: how to have multiple cascades with referencing the same tableMSSQL:如何通过引用同一个表进行多个级联
【发布时间】:2019-02-21 15:44:45
【问题描述】:

也许情况很复杂,但这是我模型的简化版本:

情况:

drop table table4
drop table table2
drop table table3
drop table table1
drop table table0

create table table0 (
    id integer not null primary key
)

create table table1 (
    id integer not null primary key
)

create table table2 (
    id integer not null primary key,
    table0_id integer not null,
    table1_id integer not null
)

create table table3 (
    id integer not null primary key,
    table1_id integer not null
)

create table table4 (
    id integer not null primary key,
    table2_id integer not null,
    table3_id integer not null
)

alter table table2 add constraint fk_table2_table0 foreign key (table0_id)
references table0 (id) on delete cascade on update no action

alter table table2 add constraint fk_table2_table1 foreign key (table1_id)
references table1 (id) on delete cascade on update no action

alter table table3 add constraint fk_table3_table1 foreign key (table1_id)
references table1(id) on delete cascade on update no action

alter table table4 add constraint fk_table4_table2 foreign key (table2_id)
references table2(id) on delete cascade on update no action

alter table table4 add constraint fk_table4_table3 foreign key (table3_id)
references table3(id) on delete no action on update no action

GO
CREATE TRIGGER WhenRowFromTable3IsDeleted ON table3
    FOR DELETE       
AS
BEGIN
    DELETE FROM table4 WHERE table3_id = (SELECT id FROM DELETED)
END
GO

INSERT INTO table0 (id) VALUES (1)
INSERT INTO table1 (id) VALUES (1)
INSERT INTO table2 (id, table0_id, table1_id) VALUES (1, 1, 1)
INSERT INTO table3 (id, table1_id) VALUES (1, 1)
INSERT INTO table4 (id, table2_id, table3_id) VALUES (1,1,1)

DELETE FROM table3 WHERE id = 1

SELECT * FROM table1, table0

结果:The DELETE statement conflicted with the REFERENCE constraint "fk_table4_table3". The conflict occurred in database "testing", table "dbo.table4", column 'table3_id'.

问题

如何从table3 中删除记录?如您所见,我已经使用触发器FOR DELETE 进行了尝试,但这会导致FK 约束错误(因此FOR DELETE 实际上是AFTER DELETE)。 我也尝试过使用 INSTEAD DELETE 但这不能使用,因为父级 (table2) 也有一个 ON DELETE CASCADE。

【问题讨论】:

  • SQL Server 没有“删除时自动删除外键约束”功能。如果您正在删除由外键引用的表,则需要先删除这些约束。我非常建议该“功能”是设计使然。我(个人)不希望我的同事在不付出努力的情况下删除约束引用的表,就好像他们确实需要删除他们需要了解含义的表(他们可能会立即寻求帮助和很快就会停止)。
  • 删除一个表和一个“记录”(行)是完全不同的。
  • 好的。所以我的问题不够清楚......我改变了它。并将删除我的 cmets。谢谢
  • 这里的问题是你的关系。您不能在fk_table4_table3 上启用级联,因为它可能导致级联循环(这是不允许的)。我怀疑如果它有上述的关系,设计可能是“有缺陷的”,但是,恐怕用我们的简化版本是不可能的。就目前而言,您必须先删除table4 中的行,然后才能进入table3
  • 谢谢。该数据库在设计时考虑了 MySQL,它可以毫无问题地处理所有 FK 包含的 ON DELETE 级联。因为应用程序必须同时支持这两个数据库。你有什么建议?在table3table4 之间添加一个表?

标签: sql-server database-trigger cascading-deletes


【解决方案1】:

通过创建一个触发器,该触发器首先删除子级表记录,然后在使用而不是 delete 后自行删除,您可以触发子触发器,就像以正确顺序执行的级联模式一样。

这通过添加更多逻辑来解决级联问题。此外,您可能希望在此处使用主键而不是 ID 来正确选择较大键上的记录。

drop table table4

drop table table2

drop table table3

drop table table1

drop table table0



create table table0 (

   id integer not null primary key

)



create table table1 (

   id integer not null primary key

)



create table table2 (

   id integer not null primary key,

   table0_id integer not null,

   table1_id integer not null

)



create table table3 (

   id integer not null primary key,

   table1_id integer not null

)



create table table4 (

   id integer not null primary key,

   table2_id integer not null,

   table3_id integer not null

)



alter table table2 add constraint fk_table2_table0 foreign key (table0_id)

references table0 (id) on delete cascade on update no action



alter table table2 add constraint fk_table2_table1 foreign key (table1_id)

references table1 (id) on delete cascade on update no action



alter table table3 add constraint fk_table3_table1 foreign key (table1_id)

references table1(id) on delete no action on update no action



alter table table4 add constraint fk_table4_table2 foreign key (table2_id)

references table2(id) on delete cascade on update no action



alter table table4 add constraint fk_table4_table3 foreign key (table3_id)

references table3(id) on delete no action on update no action



GO

CREATE TRIGGER WhenRowFromTable3IsDeleted ON table3

   INSTEAD OF DELETE      

AS

BEGIN

   DELETE FROM table4 WHERE table3_id = (SELECT id FROM DELETED)

    DELETE FROM table3 WHERE id = (SELECT id FROM DELETED)

END

GO

CREATE TRIGGER WhenRowFromTable1IsDeleted ON table1

   INSTEAD OF DELETE      

AS

BEGIN

   DELETE FROM table3 WHERE table1_id = (SELECT id FROM DELETED)

    DELETE FROM table1 WHERE id = (SELECT id FROM DELETED)

END

GO



INSERT INTO table0 (id) VALUES (1)

INSERT INTO table1 (id) VALUES (1)

INSERT INTO table2 (id, table0_id, table1_id) VALUES (1, 1, 1)

INSERT INTO table3 (id, table1_id) VALUES (1, 1)

INSERT INTO table4 (id, table2_id, table3_id) VALUES (1,1,1)



DELETE FROM table3 WHERE id = 1



SELECT * FROM table1, table0

【讨论】:

  • 这看起来像是一个解决方案。不适合编程,但我似乎可以工作!
【解决方案2】:

MSSQL 不支持多路径级联删除。

Foreign key constraint may cause cycles or multiple cascade paths?

其他 DBMS 也支持它,例如 PostgreSQL。

【讨论】:

  • 我知道这一点。但不幸的是,这并没有回答我的问题或解决我的问题。迁移到不同的数据库不是解决方案。我更改了原始帖子以使其更清晰。提前致谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-03
  • 1970-01-01
  • 2022-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-11
相关资源
最近更新 更多