如何在 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 中使用级联删除?的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server:删除表级联等效?

SQL Server - 使用递归外键级联删除

SQL Server 级联

sql中如何实现级联表的操作

sql2000 如何用触发器实现级联删除

如何理解access设置中的“级联更新”和“级联删除”?