【问题标题】:Do I need to specify ON DELETE NO ACTION on my Foreign Key?我需要在外键上指定 ON DELETE NO ACTION 吗?
【发布时间】:2013-08-01 08:25:22
【问题描述】:

我有以下用于 SQL Server 2012 的 DDL:

CREATE TABLE Subject (
   [SubjectId] INT IDENTITY (1, 1) NOT NULL,
   [Name] NVARCHAR (50) Not NULL,
   CONSTRAINT [PK_Subject] PRIMARY KEY CLUSTERED ([SubjectId] ASC)
)           

CREATE TABLE Topic (
   [TopicId] INT IDENTITY (1, 1) NOT NULL,
   [Name] NVARCHAR (50) NOT NULL,
   [SubjectId] INT NOT NULL,
   CONSTRAINT [PK_Topic] PRIMARY KEY CLUSTERED ([TopicId] ASC)
)
ALTER TABLE [Topic] WITH CHECK ADD  CONSTRAINT [FK_TopicSubject] 
   FOREIGN KEY([SubjectId]) REFERENCES [Subject] ([SubjectId]) 
   ON DELETE NO ACTION

如果子级中存在对父级的引用,我想要 SQL Server 阻止我删除父级?例如,如果有 SubjectId 为 3 的子项,我希望在 Subject 中删除 subjectID=3 失败。

对此我不清楚,似乎无法找到答案。我是否需要添加“DELETE NO ACTION”或者我可以不删除这三个词。

我问这个问题就像在一个类似的问题中一样,我有一个回答,我应该在父母身上定义一个触发器。但是我认为如果存在孩子,只需定义外键就可以阻止我删除父母。

【问题讨论】:

    标签: sql sql-server sql-server-2012


    【解决方案1】:

    来自MSDN上的column_constraint页面:

    删除时 { 无操作 |级联 |设置空 |设置默认值}

    指定对更改的表中的行执行什么操作,如果这些 行有引用关系,被引用的行被删除 从父表。默认值为NO ACTION

    所以,如果你愿意,你可以省略 ON DELETE NO ACTION,它的工作原理是一样的。

    NO ACTION 意味着当您从主题表删除到主题表时不会发生任何事情。在这种情况下,如果给定 SubjectId 在 Topic 中有一行,则您无法在不破坏参照完整性的情况下从中删除,因此将回滚删除。

    更多来自 MSDN:

    无操作 - SQL Server 数据库引擎引发错误并且 对父表中的行的删除操作被回滚。

    【讨论】:

    • Dave - 很抱歉,但我有点困惑“指定表中被更改的行会发生什么操作,如果这些行具有引用关系并且引用的行已从父级中删除桌子。”这与我的主题和主题表有关是什么意思?
    • 是的,主题是父表,主题是子表。
    • 戴夫 - 所以我说我不需要编写任何 DELETE ... 关键字是正确的,如果有一个 SubjectId= 的主题,它不会让我在主题表中删除 SubjectId=3 3 ?
    • 正确。这就是外键的工作方式。每个主题必须有一个与主题表中的行匹配的 SubjectId。如果现在不可能有​​无主题的主题。
    【解决方案2】:

    我将向您建议,虽然您可以跳过 on delete no 操作,但这样做可能不符合您的最佳利益。在表定义中指定这一点可能会阻止某人稍后添加级联删除,因为他们看到您打算不发生这种情况。当您正确地编写所有数据库对象并将它们置于源代码控制中时尤其如此,并且代码审查员会看到存在差异并询问为什么会发生这种情况。很多时候,人们太急于添加删除级联并销毁本应保留的数据(例如不再有效的客户的财务记录)。他们这样做是因为他们得到了不允许他们删除的错误,只是想摆脱它,而不是意识到这正在使他们免于犯下大错。至少如果您的表脚本中有 Delete No Action 的代码,未来的维护人员会看到这是故意的,而不仅仅是您忘记设置级联删除。当然,如果您的 dba 不允许级联删除(因为很多都不允许级联删除,并且有充分的理由!),那么这不是一个潜在的问题,但指定您的意图通常对可维护性是一件好事。

    【讨论】:

      【解决方案3】:

      “ON DELETE NO ACTION”实际上与“ON DELETE”相同。

      我同意最好用它来阐明程序员在删除“标题”时考虑了所需的操作,并决定如果存在与之相关的“行”,则不应删除“标题”。但是,我在 Visual Studio 中定义我的数据库,它拒绝将更改从“ON DELETE”更新为“ON DELETE NO ACTION”。当我刷新它时它仍然是“ON DELETE”。

      【讨论】:

        【解决方案4】:

        您可以删除关键字(这是默认设置)

        ON DELETE NO ACTION
        

        最好指定这些操作

        ON DELETE CASCADE
        

        这里有更多信息:http://msdn.microsoft.com/en-us/library/aa933119%28v=sql.80%29.aspx

        你必须编写一个触发器来确保子行没有被删除,因为我认为 SQL Server 没有ON DELETE RESTRICT这个选项

        【讨论】:

        • 好吧,你是说没有删除操作和我什么都不放是一样的吗? DELETE RESTRICT 是新事物,所以我会尝试检查一下。
        • 不只限制 Oracle 吗?
        • @DaveShaw 是的,刚刚意识到,我已经更新了,谢谢
        • Akash - 我在没有 ON DELETE 的情况下尝试了我的代码......当我试图删除一个有孩子的主题时,它不起作用。那么我真的需要触发器吗?我现在更困惑了。
        • @Akash,这不是您想要的问题吗?防止删除。
        猜你喜欢
        • 2012-10-03
        • 1970-01-01
        • 1970-01-01
        • 2014-10-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-29
        • 2023-01-24
        相关资源
        最近更新 更多