子表中的外键约束允许插入父表

时间:2016-06-27 03:54:55

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

我正在使用SQL Server 2012.我已在表上定义了外键约束。外键引用复合主键。当一列具有“00000”而其他列为空时,fk约束不起作用。父表不包含'00000'。两个fk列都有varchar数据类型。

enter image description here

以下是示例:

INSERT INTO XYZ
    ([BUSINESS_PARTNER_ID]
    ,[INDUSTRY_TYPE_CDE]
    ,[INDUSTRY_SUBTYPE_CDE])
VALUES
    (1,
    Null
    '00000')
GO

行业类型和行业子类型列从另一个表中引用。 以下是剧本:

ALTER TABLE [nfs].[xyz] WITH NOCHECK 
ADD CONSTRAINT [FK_BPMAIN__ITCDE_ISTCDE] 
FOREIGN KEY([INDUSTRY_TYPE_CDE], [INDUSTRY_SUBTYPE_CDE]) 
REFERENCES [nfs].[abc] ([INDUSTRY_TYPE_CDE], [INDUSTRY_SUBTYPE_CDE]) 
GO 

ALTER TABLE [nfs].[xyz] 
CHECK CONSTRAINT [FK_BPMAIN__ITCDE_ISTCDE] 
GO 

SQL Server在插入时不会出现任何错误。它将值插入子表中。根据我的理解,fk列可以为null,也可以包含父表中存在的值。

2 个答案:

答案 0 :(得分:2)

虽然你真的应该提供一个完整的例子,如Zohar Peled所说,你的问题可能在于外键定义中的WITH NOCHECK选项。应该CHECK使引擎启用并强制执行外键。就这样,约束不受信任。

有关使用此选项时会发生什么的示例,请参阅What is lost when I create a Foreign Key using WITH NOCHECK

答案 1 :(得分:2)

  

为什么当一个或多个列包含null时,不会检查fk约束?你能解释一下这种行为吗?

首先,我们有实际的原因。使用索引维护和检查外键。为了使索引可用,我们需要知道索引中所有列的(搜索)值。如果我们在(a,b)上有一个索引/ pk,并且我们的外键值为(NULL,1),我们就无法在索引中搜索以确定是否有任何行b值为1.这将使外键维持“昂贵”。

但其次,我们需要考虑一致性。对于单列情况,它相当无争议 - 如果您在FK列中有值,那么在引用列中需要有匹配值。否则,如果FK列为NULL,则不检查约束。

但是,我们如何将其扩展到多个列? 上面的规则是什么?没有明显的解释,而是多个。以上规则“如果所有列都是非NULL,则检查约束”或“如果任何列是非NULL,则检查约束”?当只考虑一列时,这些规则是相同的。

你希望规则是第二个,当它实际上是第一个。这是明确的documented

  

FOREIGN KEY约束可以包含空值;但是,如果复合FOREIGN KEY约束的任何列包含空值,则会跳过对构成FOREIGN KEY约束的所有值的验证。要确保验证复合FOREIGN KEY约束的所有值,请在所有参与列上指定NOT NULL。