SQL Server - 使用递归外键级联DELETE

jc_*_*jc_ 5 sql sql-server recursion cascade constraints

我花了很多时间试图弄清楚如何在SQL Server上为递归主键实现CASCADE ON DELETE一段时间了.我已经阅读了有关触发器,创建临时表等的信息,但还没有找到适用于我的数据库设计的答案.

这是一个Boss/Employee数据库示例,可用于演示目的:

TABLE employee
id|name     |boss_id
--|---------|-------
1 |John     |1
2 |Hillary  |1
3 |Hamilton |1
4 |Scott    |2
5 |Susan    |2
6 |Seth     |2
7 |Rick     |5
8 |Rachael  |5
Run Code Online (Sandbox Code Playgroud)

如您所见,每位员工都有一名也是员工的老板.所以,id/boss_id上存在PK/FK关系.

这是一个(缩写)表及其信息:

TABLE information
emp_id|street     |phone
------|-----------|-----
2     |blah blah  |blah
6     |blah blah  |blah
7     |blah blah  |blah
Run Code Online (Sandbox Code Playgroud)

employee.id/information.emp_id上有一个带有CASCADE ON DELETE的PK/FK.

例如,如果Rick被解雇,我们会这样做:

DELETE FROM employee WHERE id=7
Run Code Online (Sandbox Code Playgroud)

这应该从员工和信息中删除Rick的行.Yay级联!

现在,说我们经历了艰难时期,我们需要奠定汉密尔顿和他的整个部门.这意味着我们需要删除

  • 汉密尔顿
  • 斯科特
  • 苏珊
  • 赛斯
  • 干草堆
  • 瑞秋

我们运行时从员工和信息表中:

DELETE FROM employee WHERE id=3
Run Code Online (Sandbox Code Playgroud)

我为id/emp_id尝试了一个简单的CASCADE ON DELETE,但SQL Server没有它:

Introducing FOREIGN KEY constraint 'fk_boss_employee' on table 'employee' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Run Code Online (Sandbox Code Playgroud)

我能够在Access中的测试数据库上使用CASCADE ON DELETE,它的行为完全符合我的要求.同样,如果父母,祖父母,曾祖父母等被删除,我希望删除父母的每个可能的孩子,孙子,曾孙等.

当我尝试使用触发器时,我似乎无法触发它(例如,当你试图删除汉密尔顿的员工Susan时,先看看Susan是否有员工等)更不用说减少N名员工了.

所以!我想我已经提供了我能想到的每一个细节.如果仍然不清楚,我会尝试改进这种描述.

Ste*_*ger 5

Necromancing.
有两个简单的解决方案.

  • 你可以阅读微软的遗憾原因,告诉他们为什么没有实现这一点(因为它既困难又耗时 - 时间就是金钱),并解释你为什么不/不需要它(尽管如此),并在存储过程中使用游标实现delete-function
    • 因为你真的不需要删除级联,因为你总是有时间随时随地改变所有你和所有其他人的代码(比如与其他系统的接口),删除员工(或员工,注:复数)(包括所有上级和下级对象[包括添加一个或几个新对象时]在此数据库中(以及此数据库的任何其他副本供其他客户使用,尤其是在您无法访问数据库时的生产中[哦,和在测试系统,集成系统,以及生产,测试和集成的本地副本]

要么

  • 您可以使用实际支持递归级联删除的正确DBMS,例如PostGreSQL(只要图是定向的,非循环的;否则删除时出现ERROR).

PS:
那是讽刺.


Kev*_*cki 3

以下内容可能适合您(我尚未测试它,因此可能需要一些调整)。似乎您所要做的就是删除层次结构底部的员工,然后再删除较高的员工。使用 CTE 递归地构建删除层次结构,并按员工的层次结构级别对 CTE 输出进行降序排序。然后按顺序删除。

CREATE PROC usp_DeleteEmployeeAndSubordinates (@empId INT)
AS

;WITH employeesToDelete AS (
    SELECT  id, CAST(1 AS INT) AS empLevel
    FROM    employee
    WHERE   id = @empId
    UNION ALL
    SELECT  e.id, etd.empLevel + 1
    FROM    employee e
            JOIN employeesToDelete etd ON e.boss_id = etd.id AND e.boss_id != e.id
)
SELECT  id, ROW_NUMBER() OVER (ORDER BY empLevel DESC) Ord
INTO    #employeesToDelete
FROM    employeesToDelete;

DECLARE @current INT = 1, @max INT = @@ROWCOUNT;

WHILE @current <= @max
BEGIN
    DELETE employee WHERE id = (SELECT id FROM #employeesToDelete WHERE Ord = @current);
    SET @current = @current + 1;
END;
GO
Run Code Online (Sandbox Code Playgroud)