如何在 SQL Server 中使用级联删除?
Posted
技术标签:
【中文标题】如何在 SQL Server 中使用级联删除?【英文标题】:How do I use cascade delete with SQL Server? 【发布时间】:2011-09-09 18:45:17 【问题描述】:我有 2 个表:T1 和 T2,它们是包含数据的现有表。我们在 T1 和 T2 之间有一对多的关系。当删除 T1 中的记录时,如何更改表定义以在 SQL Server 中执行级联删除,同时删除 T2 中的所有关联记录。
它们之间存在外部约束。我不想删除表或创建触发器来删除 T2。例如,当我删除一个员工时,所有的评论记录也应该消失了。
T1 - 员工,
Employee ID
Name
Status
T2 - 绩效评估,
Employee ID - 2009 Review
Employee ID - 2010 Review
【问题讨论】:
【参考方案1】:你需要,
删除现有的外键约束, 在启用ON DELETE CASCADE
设置的情况下添加一个新的。
类似:
ALTER TABLE dbo.T2
DROP CONSTRAINT FK_T1_T2 -- or whatever it's called
ALTER TABLE dbo.T2
ADD CONSTRAINT FK_T1_T2_Cascade
FOREIGN KEY (EmployeeID) REFERENCES dbo.T1(EmployeeID) ON DELETE CASCADE
【讨论】:
我和我的团队刚刚做到了这一点。我们不得不放弃我们的约束并重新添加它们。这对我们有用。 这有利于硬删除吗?软删除永远不会有约束问题。对我来说似乎完全相反。 @Maxx 在硬删除中,您删除一条记录,无需担心孤立寄存器,而在软删除中,您需要手动执行。【参考方案2】:在 SQL Server Management Studio 中将“级联删除”添加到现有外键:
首先,选择您的外键,然后在新的查询窗口中打开它的“DROP and Create To..”。
然后,只需将ON DELETE CASCADE
添加到ADD CONSTRAINT
命令:
并点击“执行”按钮运行此查询。
顺便说一句,要获取外键列表,并查看哪些外键打开了“级联删除”,您可以运行此脚本:
SELECT
OBJECT_NAME(f.parent_object_id) AS 'Table name',
COL_NAME(fc.parent_object_id,fc.parent_column_id) AS 'Field name',
delete_referential_action_desc AS 'On Delete'
FROM sys.foreign_keys AS f,
sys.foreign_key_columns AS fc,
sys.tables t
WHERE f.OBJECT_ID = fc.constraint_object_id
AND t.OBJECT_ID = fc.referenced_object_id
ORDER BY 1
如果您发现由于外键约束而无法 DROP
特定表,但您无法确定是哪个 FK 导致了问题,那么您可以运行以下命令:
sp_help 'TableName'
那篇文章中的 SQL 列出了所有引用特定表的 FK。
希望这一切对您有所帮助。
对长手指表示歉意。我只是想说明一点。
【讨论】:
手指立即卖掉了这个答案。 我刚刚从搜索引擎结果页面的“删除级联图像”部分点击到这里,纯粹是因为手指。那东西怎么了。 感谢您提到 sp_help,以前从未见过,但显然非常有用! 我觉得手指撒谎很多......【参考方案3】:您可以使用 SQL Server Management Studio 完成此操作。
→ 右键单击表设计并转到关系并在左侧窗格中选择外键,在右侧窗格中展开菜单“插入和更新规范”并选择“级联”作为删除规则。
【讨论】:
你好,这4个有什么区别,打开级联是否可以轻松删除表中的所有数据。如何查看所有依赖项/fk 键 on 此表,而不是来自此表。即使删除所有 FK 后,我仍然会收到错误 @aggie - 您可以通过以下方式检查依赖关系 - 右键单击表 ->“查看依赖关系”此外,sql server 还会为您提供详细的错误,其中包含表名和列名,例如“DELETE 语句冲突具有 REFERENCE 约束“FK_Child1_Parent1”。冲突发生在数据库“TESTDB”、表“dbo.Child1”、列“Parent1ID”中。” @aggie - 第四种情况“设置默认值”是,您必须在外键列中设置默认约束,当我们删除父表时,默认值将在子表中替换。 (注意:默认值必须与父表匹配。)更多信息请访问mssqltips.com/sqlservertip/2365/… 这很有帮助。我想知道,为什么没有插入规则?也就是说,当我在 T1 中添加一行时,我希望在 T2 中自动创建相应的条目。 @RobertM。因为那没有任何意义。它怎么知道 INSERT 的值是什么?您也许可以使用 INSERT 触发器来生成子行,尝试研究一下。【参考方案4】:使用类似的东西
ALTER TABLE T2
ADD CONSTRAINT fk_employee
FOREIGN KEY (employeeID)
REFERENCES T1 (employeeID)
ON DELETE CASCADE;
填写正确的列名,你应该设置。正如mark_s 正确指出的那样,如果您已经有一个外键约束,您可能需要先删除旧的,然后再创建新的。
【讨论】:
@marc_s - 实际上,您可以针对两边完全相同的列添加第二个外键,它会正常工作。如果在没有停机时间的生产环境中工作,最好通过级联引入新的 FK,然后删除旧的 FK,而不是在没有 FK 的情况下在桌面上留下一个窗口。 (刚刚在 SQL 2008 上测试过) 这是正确的。我试过这个,它有效。无需删除第一个外键约束。感谢您的回复。【参考方案5】:ON DELETE CASCADE
指定删除父数据时删除子数据。
CREATE TABLE products
( product_id INT PRIMARY KEY,
product_name VARCHAR(50) NOT NULL,
category VARCHAR(25)
);
CREATE TABLE inventory
( inventory_id INT PRIMARY KEY,
product_id INT NOT NULL,
quantity INT,
min_level INT,
max_level INT,
CONSTRAINT fk_inv_product_id
FOREIGN KEY (product_id)
REFERENCES products (product_id)
ON DELETE CASCADE
);
对于这个外键,我们指定了ON DELETE CASCADE
子句,它告诉SQL Server在删除父表中的数据时,删除子表中对应的记录。所以在本例中,如果从 products 表中删除了 product_id 值,则 inventory 表中使用该 product_id 的对应记录也将被删除。
【讨论】:
【参考方案6】:首先启用 ONCascade 属性:
1.删除已有的外键约束
2.在启用 ON DELETE CASCADE 设置的情况下添加一个新的
例如:
IF EXISTS(SELECT 1 FROM sys.foreign_keys WHERE parent_object_id = OBJECT_ID(N'dbo.Response'))
BEGIN
ALTER TABLE [dbo].[Response] DROP CONSTRAINT [FK_Response_Request]
ALTER TABLE [dbo].[Response] WITH CHECK ADD CONSTRAINT [FK_Response_Request] FOREIGN KEY([RequestId])
REFERENCES [dbo].[Request] ([RequestId])
ON DELETE CASCADE
END
ELSE
BEGIN
ALTER TABLE [dbo].[Response] WITH CHECK ADD CONSTRAINT [FK_Response_Request] FOREIGN KEY([RequestId])
REFERENCES [dbo].[Request] ([RequestId])
ON DELETE CASCADE
END
第二次禁用 ONCascade 属性:
1.Drop现有的外键约束
2.在启用 ON DELETE NO ACTION 设置的情况下添加一个新的
例如:
IF EXISTS(SELECT 1 FROM sys.foreign_keys WHERE parent_object_id = OBJECT_ID(N'dbo.Response'))
BEGIN
ALTER TABLE [dbo].[Response] DROP CONSTRAINT [FK_Response_Request]
ALTER TABLE [dbo].[Response] WITH CHECK ADD CONSTRAINT [FK_Response_Request] FOREIGN KEY([RequestId])
REFERENCES [dbo].[Request] ([RequestId])
ON DELETE CASCADE
END
ELSE
BEGIN
ALTER TABLE [dbo].[Response] WITH CHECK ADD CONSTRAINT [FK_Response_Request] FOREIGN KEY([RequestId])
REFERENCES [dbo].[Request] ([RequestId])
ON DELETE NO ACTION
END
【讨论】:
【参考方案7】:如果一对多关系是从 T1 到 T2,那么它不代表一个函数,因此不能用于推导或推断一个反函数,以保证生成的 T2 值不会省略 T1 连接 T2 的元组是演绎有效的,因为没有演绎有效的反函数。 (表示函数是主键的目的。)SQL 中的答案认为是的,你可以做到。关系思维的答案是否定的,你做不到。请参阅 Codd 1970 中的歧义点。从 T1 到 T2 的关系必须是多对一的。
【讨论】:
【参考方案8】:我认为你不能只删除表属性,如果这是实际的生产数据,只删除不影响表架构的内容。
【讨论】:
这是重申 OP 不想删除表的观点,OP 希望找到一种方法来为现有表实现级联删除。如果您想质疑此类请求的有效性,应将其作为对原始帖子的评论来完成。如果您没有足够的代表,请提供 OPs 问题的解决方案。以上是关于如何在 SQL Server 中使用级联删除?的主要内容,如果未能解决你的问题,请参考以下文章