【问题标题】:SQL Server : table with foreign key to itself with cascade deleteSQL Server:具有外键的表与级联删除
【发布时间】:2016-08-17 04:44:46
【问题描述】:

我需要一个表格来保存这样的层次结构树数据(即大陆、国家、城市)

id  name    parent
-------------------
1   world   null
2   Europe  1
3   Asia    1
4   France  2
5   Paris   4
6   Lyon    4

我想删除 France 并希望该表级联删除所有法国城市。但是当我像这样创建表格时

create table locations 
(
    id int identity(1, 1),
    name varchar(255) not null,
    parent_id int,

    constraint pk__locations
        primary key clustered (id),

    constraint fk__locations
        foreign key (parent_id) 
            references locations (id)
                on delete cascade
                on update no action 
)

我遇到了一个错误

在表上引入 FOREIGN KEY 约束“fk__locations” “位置”可能会导致循环或多个级联路径。指定开 DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。

信息说

  1. 指定ON DELETE NO ACTION - 这正是我不想要的
  2. 指定ON UPDATE NO ACTION - 指定
  3. 修改其他 FOREIGN KEY 约束 - 我不明白这个

谁能帮忙?

【问题讨论】:

标签: sql-server tsql


【解决方案1】:

这是不可能的。你可以通过INSTEAD OF TRIGGER解决这个问题

create table locations 
(
    id int identity(1, 1),
    name varchar(255) not null,
    parent_id int,

    constraint pk__locations
        primary key clustered (id)

)
GO

INSERT INTO locations(name,parent_id)  VALUES
 ('world',null)
,('Europe',1)
,('Asia',1)
,('France',2)
,('Paris',4)
,('Lyon',4);
GO

--此触发器将使用递归 CTE 来获取您要删除的所有 ID 之后的所有 ID。这些 ID 将被删除。

CREATE TRIGGER dbo.DeleteCascadeLocations ON locations
INSTEAD OF DELETE 
AS
BEGIN
    WITH recCTE AS
    (
        SELECT id,parent_id
        FROM deleted

        UNION ALL

        SELECT nxt.id,nxt.parent_id
        FROM recCTE AS prv
        INNER JOIN locations AS nxt ON nxt.parent_id=prv.id
    )
    DELETE FROM locations WHERE id IN(SELECT id FROM recCTE);
END
GO

--在这里测试一下,用不同的ID试试。你也可以试试WHERE id IN(4,3)...

SELECT * FROM locations;

DELETE FROM locations WHERE id=4;

SELECT * FROM locations
GO

--清理(注意真实数据!)

if exists(select 1 from INFORMATION_SCHEMA.TABLES where TABLE_NAME='locations')
---DROP TABLE locations;

【讨论】:

  • @delid 没有在任何地方使用,这可能是递归触发器吗?
  • @Bijujose,谢谢,@delid 是测试中被遗忘的残留物......递归触发器有什么优势?递归 CTE 将从给定 ID 获取整个分支,直到深度为 100(默认情况下)。所有相关行将在一个语句中删除。这应该是最大的最优解;-)
  • 不,不是优势,我在想,因为我们要从同一个表中删除,所以触发器会无限期地触发?
  • @Bijujose 没问题...INSTEAD OF TRIGGER 是一个一次性操作,它发生而不是正常的删除过程.
  • 嘿@Shnugo,你用一个答案打了两个问题 :) 很抱歉重复了这个Self-referencing constraint in MS SQL
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-05
  • 1970-01-01
  • 2015-12-08
  • 1970-01-01
  • 2011-06-19
  • 1970-01-01
相关资源
最近更新 更多