Sql 子表中的外键约束允许插入与';t存在于父表中

Sql 子表中的外键约束允许插入与';t存在于父表中,sql,sql-server,sql-server-2012,constraints,Sql,Sql Server,Sql Server 2012,Constraints,我正在使用SQL Server 2012。我已经在表上定义了外键约束。外键引用复合主键。当一列具有“00000”而另一列为空时,fk约束不起作用。父表不包含“00000”。两个fk列都具有varchar数据类型 下面是一个例子: INSERT INTO XYZ ([BUSINESS_PARTNER_ID] ,[INDUSTRY_TYPE_CDE] ,[INDUSTRY_SUBTYPE_CDE]) VALUES (1, Null '00000')

我正在使用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,或者应该包含父表中存在的值。

虽然您确实应该提供一个完整的示例,如Zohar Peled所说,但您的问题可能在于外键定义中的
WITH NOCHECK
选项。应
CHECK
以使外键由发动机启用和强制。事实上,约束是不可信的

有关使用此选项时发生的情况的示例,请参见

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

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

第二,我们需要考虑一致性。对于单列的情况,这是完全没有争议的-如果FK列中有一个值,那么引用的列中需要有一个匹配的值。否则,如果FK列为
NULL
,则不检查约束

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

您希望规则是第二条,而事实上它是第一条。这是明确的:

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


你能写下你的FK并发布它吗?我不知道FK可能在两列上。问题是您不应该被允许输入空值吗?除了Nick提到的以外,请发布错误以及Sql server没有给出任何错误。它在子表中插入值。请编辑您的问题以包括-这意味着样本表DDL、样本数据DML和所需输出。遗憾的是,当一个或多个列为
NULL
时,外键未被选中。您需要将您的设计修改为不使用
NULL
s的设计,就像它们是实际值一样。在我的外键脚本中,首先我定义了约束,没有检查。创建约束后,在fk上定义了check约束。@Damien提供了正确答案。我不知道复合外键在null中的行为方式。