sql2000 如何用触发器实现级联删除
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql2000 如何用触发器实现级联删除相关的知识,希望对你有一定的参考价值。
参考技术A 下面是在user表上建立触发器的语句,在topic上建触发器的语句类似CREATE
TRIGGER
deleteuser
ON
[dbo].[user]
INSTEAD
OF
DELETE
AS
DECLARE
@id
int;
--把数据类型改成与user_id一致
SELECT
@id=user_id
from
deleted;
DELETE
FROM
UT
WHERE
user_id=@id;
DELETE
FROM
user
WHERE
user_id=@id;
你把级联
DELETE
或
UPDATE取消掉就行了 参考技术B delete
user
where
user_id
in
(select
user_id
from
UT
where
1=1)
delete
topic
where
topic_id
in
(select
topic_id
from
UT
where
1=1)
无须触发器.
直接用子删除语句即可实现.
不知满意否>
如果一定要用
也可以留言给我
继续作答
SQL Server - 使用递归外键级联删除
【中文标题】SQL Server - 使用递归外键级联删除【英文标题】:SQL Server - Cascading DELETE with Recursive Foreign Keys 【发布时间】:2014-09-05 21:53:45 【问题描述】:一段时间以来,我花了很多时间试图弄清楚如何为 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
如您所见,每个员工都有一个老板,老板也是员工。所以,在id/boss_id上有PK/FK的关系。
这是一个包含他们信息的(缩写)表:
TABLE information
emp_id|street |phone
------|-----------|-----
2 |blah blah |blah
6 |blah blah |blah
7 |blah blah |blah
employee.id/information.emp_id 上有一个带有 CASCADE ON DELETE 的 PK/FK。
例如,如果 Rick 被解雇,我们会这样做:
DELETE FROM employee WHERE id=7
这应该从员工和信息中删除 Rick 的行。耶级联!
现在,假设我们经历了艰难时期,我们需要让汉密尔顿和他的整个部门休息。这意味着我们需要删除
汉密尔顿 斯科特 苏珊 赛斯 瑞克 瑞秋我们运行时从员工表和信息表中:
DELETE FROM employee WHERE id=3
我为 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.
我能够在 Access 中的测试数据库上使用 CASCADE ON DELETE,它的行为完全符合我的要求。同样,如果父母、祖父母、曾祖父母等被删除,我希望删除父母的每个可能的孩子、孙子女、曾孙子女等。
当我尝试使用触发器时,我似乎无法让它自行触发(例如,当您尝试删除 Hamilton 的员工 Susan 时,首先查看 Susan 是否有任何员工等),更不用说下降 N 个员工。
所以!我想我已经提供了我能想到的每一个细节。如果还有什么不清楚的地方,我会尝试改进这个描述。
【问题讨论】:
【参考方案1】:这听起来可能很极端,但我认为没有一个简单的选项可以满足您的需求。我建议创建一个可以执行以下操作的 proc:
-
禁用 FK 约束
使用递归 CTE 获取要删除的员工列表(将其保存在临时表中)
从父/子表中删除行
从员工信息表中删除行
启用 FK 约束
将整个事物包装在事务中以保持一致性
【讨论】:
你不需要禁用 FK,如果你使用 Delete from employee WHERE id in ( /* SOME CTE EXPR */ ) Sql server 将检查所有引用是否都在删除的对象中有了它【参考方案2】:以下内容可能对您有用(我尚未对其进行测试,因此可能需要进行一些调整)。似乎您所要做的就是在删除更高级别的员工之前从层次结构的底部删除员工。使用 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
【讨论】:
修复了一些语法问题后,我可以确认这个过程完全符合我的要求。非常感谢!【参考方案3】:死灵术。 有2个简单的解决方案。
您可以阅读 Microsoft 的抱歉理由,说明他们为什么不这样做 实现这一点(因为它既困难又耗时 - 时间就是金钱),并解释为什么你不需要/不应该需要它(尽管你这样做),并使用存储的游标实现删除功能程序 因为您实际上并不需要删除级联,因为您总是有时间随时随地更改您和所有其他人的代码(如与其他系统的接口),以删除员工(或员工,注意:复数)(包括所有上级和下级对象[包括添加一个或多个新对象时])(以及其他客户的此数据库的任何其他副本,尤其是在生产中当您无权访问数据库时[哦,关于测试系统、集成系统以及生产、测试和集成的本地副本]或
您可以使用适当的 DBMS,它实际上支持递归级联删除,例如 PostGreSQL(只要图形是有向的且非循环的;否则删除时出现错误)。PS:这是讽刺。
注意:
只要您的删除不是源于级联,并且您只是想对自引用表执行删除,您就可以删除任何条目,只要您删除所有从属对象以及 in-条款。
所以要删除这样的对象,请执行以下操作:
;WITH CTE AS
(
SELECT id, boss_id, [name] FROM employee
-- WHERE boss_id IS NULL
WHERE id = 2 -- <== this here is the id you want to delete !
UNION ALL
SELECT employee.id, employee.boss_id, employee.[name] FROM employee
INNER JOIN CTE ON CTE.id = employee.boss_id
)
DELETE FROM employee
WHERE employee.id IN (SELECT id FROM CTE)
假设你有如下表结构:
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.employee') AND type in (N'U'))
BEGIN
CREATE TABLE dbo.employee
(
id int NOT NULL,
boss_id int NULL,
[name] varchar(50) NULL,
CONSTRAINT PK_employee PRIMARY KEY ( id )
);
END
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'dbo.FK_employee_employee') AND boss_id_object_id = OBJECT_ID(N'dbo.employee'))
ALTER TABLE dbo.employee WITH CHECK ADD CONSTRAINT FK_employee_employee FOREIGN KEY(boss_id)
REFERENCES dbo.employee (id)
GO
IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'dbo.FK_employee_employee') AND boss_id_object_id = OBJECT_ID(N'dbo.employee'))
ALTER TABLE dbo.employee CHECK CONSTRAINT FK_employee_employee
GO
【讨论】:
撇开讽刺不谈,微软真的为此做了抱歉的借口吗?有参考吗?以上是关于sql2000 如何用触发器实现级联删除的主要内容,如果未能解决你的问题,请参考以下文章