【问题标题】:SQL Cascade Delete with multiple columns具有多列的 SQL 级联删除
【发布时间】:2023-03-12 08:35:02
【问题描述】:

我有一个名为 [Content] 的 SQL 表,其中包含以下列:

  • ID PrimaryKey,唯一标识符,不为空
  • 文件唯一标识符,不为空
  • FileHighResolutionID 唯一标识符,不为空
  • FileHighResolutionProID 唯一标识符,不为空
  • FileVectorID 唯一标识符,不为空
  • ThumbnailID 唯一标识符,不为空

第一列值是自动生成的。 其余五列值引用名为 [File]

的表的 ID

当我从 [Content] 中删除一行时,我还想删除 [File].[ID] 中 [File] 中的行 匹配 [Content].[File][Content].[HighResolutionID] 等中的值。

由于这与多个列相关联,级联删除是否有效?如果有,语法是什么。

我能想到的最好的:

ALTER TABLE [dbo].[File]
ADD CONSTRAINT fk_content_file
FOREIGN KEY (FileID)
REFERENCES [dbo].[File] (ID)
ON DELETE CASCADE;

ALTER TABLE [dbo].[File]
ADD CONSTRAINT fk_content_filehighresolution
FOREIGN KEY (FileHighResolutionID)
REFERENCES [dbo].[File] (ID)
ON DELETE CASCADE;

ALTER TABLE [dbo].[File]
ADD CONSTRAINT fk_content_highresolutionpro
FOREIGN KEY (FileHighResolutionProID)
REFERENCES [dbo].[File] (ID)
ON DELETE CASCADE;

ALTER TABLE [dbo].[File]
ADD CONSTRAINT fk_content_vector
FOREIGN KEY (FileVectorID)
REFERENCES [dbo].[File] (ID)
ON DELETE CASCADE;

ALTER TABLE [dbo].[File]
ADD CONSTRAINT fk_content_thumbnail
FOREIGN KEY (ThumbnailID)
REFERENCES [dbo].[File] (ID)
ON DELETE CASCADE;

...但我不确定这是否正确。我宁愿更确切地知道,也不愿丢失迄今为止已填充到应用程序中的数据。

【问题讨论】:

  • FWIW,我使用存储过程来处理这类事情。它让我更难做一些非常愚蠢的事情并让它通过数据愉快地级联,它允许验证额外的标准,用户可以被授予对 SP 的访问权限而无需访问基础表,SP 可以进行额外的日志记录,. .. .

标签: sql-server tsql sql-server-2014


【解决方案1】:

我认为在您的情况下ON DELETE CASCADE 不是正确的工具。如果您从[File] 中删除一行,级联删除将为您做的是从[Content] 中删除行,但我认为您想要相反的方式。

这可以通过[Content] 上的触发器来实现,但要确保从[File] 中删除该行是安全的,您需要检查它是否没有在您的[Content] 的其他地方被引用先表(除非你真的,真的确保每个文件只被引用一次)。

这是一个可以为您执行此操作的触发器示例。请注意,我只在[Content] 表中实现了几个字段,我相信您可以填写其余字段。

设置

Create Table [file] (
    FileID int Primary Key Clustered);
Create Table [content] (
    ID int,
    [File] int Constraint fFile_content References [file] (FileID),
    [FileHighResolution] int Constraint fFileHighResolution_content References [file] (FileID));

Insert Into [file] (FileID)
Values  (1), (2), (3);

Insert Into [content] (ID, [File], FileHighResolution)
Values  (1, 1, 2),
        (2, 1, 3);

触发器

Create Trigger trg_Delete_Remove_Unused_File On [content] After Delete As
Begin
    Delete From [file]
      From [file] As f
      Join Deleted As d
        On f.FileID = d.[File]
      Where Not Exists (Select 1 
                          From [content]
                          Where [file] = d.[File]
                             Or FileHighResolution = d.[File]);

    Delete From [file]
      From [file] As f
      Join Deleted As d
        On f.FileID = d.FileHighResolution
      Where Not Exists (Select 1 
                          From [content]
                          Where [file] = d.FileHighResolution
                             Or FileHighResolution = d.FileHighResolution);
End

之前

FileID  
1
2
3

ID   File   FileHighResolution
1    1      2
2    1      3

验证

Delete From [content] Where ID = 1;

之后

FileID
1
3

ID   File   FileHighResolution
2    1      3

文件 2 已从 [File] 表中删除,因为它被从 [Content] 删除的行引用 并且它未被 [Content] 中的任何其他行引用。文件 1 未被从 [File] 删除,即使它被已删除的行引用,因为它被另一行引用,但未被删除。

您可能需要针对性能进行优化,但这在逻辑上应该是合理的。

【讨论】:

  • 请注意,我仍然在我的表上添加了参照完整性约束,您也应该这样做。
  • 太棒了!我会在早上到办公室时试试这个。
  • 只是想跟上。内部选择中的 OR 条件真的有必要吗?在我的例子中,FileHighResolutionID 和 FileID 列永远不能绑定到 File 中的同一行(从应用程序的角度来看是强制的)。
  • @eat-sleep-code 当然,如果你知道这是真的,那么OR 就不需要了。只需加入同一领域。
猜你喜欢
  • 2013-08-21
  • 1970-01-01
  • 2011-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多