我正在使用SQL Server 2012.我已在表上定义了外键约束。外键引用复合主键。当一列具有“00000”而其他列为空时,fk约束不起作用。父表不包含'00000'。两个fk列都有varchar
数据类型。
以下是示例:
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,也可以包含父表中存在的值。
答案 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。