请为我澄清两件事:
据我所知,NULL
不应该用在外键中,但在我的某些应用程序中,我可以在Oracle和SQL Server中输入NULL
,而且我不会不知道为什么。
答案 0 :(得分:429)
简答:是的,它可以是NULL或重复。
我想解释为什么外键可能需要为null或者可能需要唯一或不唯一。首先要记住,外键只需要该字段中的值必须首先存在于另一个表(父表)中。根据定义,这就是FK。根据定义,空值不是值。 Null意味着我们还不知道它的价值是什么。
让我举一个现实生活中的例子。假设您有一个存储销售提案的数据库。进一步假设每个提案仅分配了一个销售人员和一个客户。因此,您的提议表将有两个外键,一个具有客户端ID,另一个具有销售代表ID。但是,在创建记录时,并不总是分配销售代表(因为没有人可以自由处理它),因此填写了客户端ID,但销售代表ID可能为空。换句话说,当您在输入数据时可能不知道其值时,通常需要具有空FK的能力,但是您知道表中需要输入的其他值。要允许FK中的空值,通常您只需要在具有FK的字段上允许空值。 null值与它是FK的想法是分开的。
它是唯一的还是不唯一的,与表是否与父表具有一对一或一对多的关系有关。现在,如果你有一对一的关系,你有可能将数据全部放在一个表中,但如果表格太宽或者数据是在另一个主题上(员工 - 保险示例@tbone给出了)例如),那么你想要一个带有FK的单独表。然后你想要使这个FK也是PK(它保证唯一性)或对它施加一个独特的约束。
大多数FK用于一对多的关系,这是你从FK获得的,而不在场上添加进一步的约束。所以你有一个订单表和订单详情表。如果客户一次订购十件商品,他有一个订单和十个订单明细记录,其中包含与FK相同的订单ID。
答案 1 :(得分:46)
1 - Yes, since at least SQL Server 2000.
2 - 是的,只要它不是UNIQUE
约束或链接到唯一索引。
答案 2 :(得分:38)
从马的嘴里说:
外键允许全部为NULL的键值,即使没有 匹配PRIMARY或UNIQUE键
外键没有限制
如果没有在外键上定义任何其他约束,则为任何数字 子表中的行可以引用相同的父键值。 此模型允许外键中的空值。 ...
外键上的NOT NULL约束
当不允许空值时 一个外键,子表中的每一行必须显式引用一个 父键中的值,因为外部不允许空值 键。
子表中的任意数量的行都可以引用同一个父级 键值,因此该模型建立了一对多的关系 在父键和外键之间。但是,孩子的每一行 table必须具有父键值的引用;缺席了 不允许外键中的值(null)。同样的例子 上一节可以用来说明这种关系。 但是,在这种情况下,员工必须具有特定的参考 部。
外键上的UNIQUE约束
当UNIQUE约束是 在外键上定义,子表中只有一行可以 引用给定的父键值。该模型允许空值 外键。
此模型在父级之间建立一对一的关系 和允许未确定值(空值)的外键 外键。例如,假设employee表有一列 名为MEMBERNO,指的是员工会员编号 公司保险计划。此外,名为INSURANCE的表具有主表 键名为MEMBERNO,表中的其他列保持各自 有关员工保险单的信息。 MEMBERNO in employee表必须是外键和唯一键:
在EMP_TAB和EMP_TAB之间强制实施参照完整性规则 保险表(FOREIGN KEY约束)
保证每位员工都有一个唯一的会员编号( UNIQUE键约束)
外键上的UNIQUE和NOT NULL约束
两者都是UNIQUE 和NOT NULL约束是在外键上定义的,只有一行 在子表中可以引用给定的父键值,因为 子项中的每一行中都不允许使用NULL值 table必须显式引用父键中的值。
见:
答案 3 :(得分:15)
是的,外键可以为null,如上面高级程序员所说......我会添加另一个场景,其中外键需要为null .... 假设我们在应用程序中有表格注释,图片和视频,允许对图片和视频进行评论。在注释表中,我们可以有两个外键PicturesId,以及VideosId和主键CommentId。因此,当您对视频发表评论时,仅需要VideosId并且pictureId将为null ...如果您对图片发表评论,则只需要PictureId,而且VideosId将为null ...
答案 4 :(得分:5)
这取决于此foreign key
在您的关系中扮演的角色。
foreign key
在您的关系中也是key attribute
,则不能为空foreign key
是您关系中的普通属性,则可以为NULL。答案 5 :(得分:3)
以下是使用Oracle语法的示例:
首先让我们创建一个表COUNTRY
CREATE TABLE TBL_COUNTRY ( COUNTRY_ID VARCHAR2 (50) NOT NULL ) ;
ALTER TABLE TBL_COUNTRY ADD CONSTRAINT COUNTRY_PK PRIMARY KEY ( COUNTRY_ID ) ;
创建表PROVINCE
CREATE TABLE TBL_PROVINCE(
PROVINCE_ID VARCHAR2 (50) NOT NULL ,
COUNTRY_ID VARCHAR2 (50)
);
ALTER TABLE TBL_PROVINCE ADD CONSTRAINT PROVINCE_PK PRIMARY KEY ( PROVINCE_ID ) ;
ALTER TABLE TBL_PROVINCE ADD CONSTRAINT PROVINCE_COUNTRY_FK FOREIGN KEY ( COUNTRY_ID ) REFERENCES TBL_COUNTRY ( COUNTRY_ID ) ;
这在Oracle中运行得非常好。请注意,第二个表中的COUNTRY_ID外键没有“NOT NULL”。
现在要在PROVINCE表中插入一行,仅指定PROVINCE_ID就足够了。但是,如果您也选择指定COUNTRY_ID,则它必须已存在于COUNTRY表中。
答案 6 :(得分:1)
默认情况下,外键没有约束,外键可以为null并重复。
在创建表/更改表时,如果添加任何唯一性约束或不为null,则只有它不允许空/重复值。
答案 7 :(得分:0)
简单地说,实体之间的“非识别”关系是ER-Model的一部分,在设计ER-Diagram时可以在Microsoft Visio中使用。这需要在“零或大于零”或“零或一”类型的实体之间强制实现基数。注意基数中的这个“零”而不是“一对多”中的“一”。
现在,基数可能为“零”(非识别)的非识别关系的例子是当我们说一个实体中的记录/对象时 - “可能”或“可能不”具有作为参考的值到另一个实体-B的记录。
因为,实体-A的一条记录有可能将自己标识为其他实体-B的记录,因此实体-B中应该有一列具有实体记录的标识值 - B.如果实体-A中的记录没有标识实体-B中的记录/或(对象/ s),则该列可以是“空”。
在面向对象(真实世界)范例中,有些情况下,类B的对象不一定依赖于(强耦合)在类A的对象上它的存在,这意味着类B是松散耦合的使用A类使得A类可以“包含”(包含)A类对象,而B类对象的概念必须具有(组合)A类对象,因为它(对象) B类创造。
从SQL Query的角度来看,您可以查询entity-B中为Entity-B保留的外键的“非null”的所有记录。这将为实体-A中的行带来具有特定对应值的所有记录,或者所有具有Null值的记录将是在实体-B中的实体-A中没有任何记录的记录。
答案 8 :(得分:0)
外键的概念基于引用主表中已经存在的值的概念。这就是为什么在另一个表中将其称为外键的原因。这个概念称为参照完整性。如果将外键声明为空字段,则将违反引用完整性的逻辑。它指的是什么?它只能引用主表中存在的内容。因此,我认为将外键字段声明为null是错误的。
答案 9 :(得分:0)
外键可以为NULL吗?
现有答案集中在单列情况下。如果考虑使用多列外键,则可以使用SQL标准中定义的MATCH [SIMPLE | PARTIAL | FULL]
子句来选择更多选项:
使用给定的匹配类型,将插入到引用列中的值与引用表和引用列的值进行匹配。共有三种匹配类型:“完全匹配”,“部分匹配”和“简单匹配”(默认)。 MATCH FULL (全部匹配)不允许多列外键的一列为空,除非所有外键列均为空;如果它们全为空,则不需要该行在引用表中具有匹配项。 MATCH SIMPLE (MATCH SIMPLE )允许任何外键列为空;如果它们中的任何一个为null,则不需要该行在引用表中具有匹配项。 MATCH PARTIAL 尚未实现。
(当然,可以将NOT NULL约束应用于引用列,以防止出现这些情况。)
示例:
CREATE TABLE A(a VARCHAR(10), b VARCHAR(10), d DATE , UNIQUE(a,b));
INSERT INTO A(a, b, d)
VALUES (NULL, NULL, NOW()),('a', NULL, NOW()),(NULL, 'b', NOW()),('c', 'b', NOW());
CREATE TABLE B(id INT PRIMARY KEY, ref_a VARCHAR(10), ref_b VARCHAR(10));
-- MATCH SIMPLE - default behaviour nulls are allowed
ALTER TABLE B ADD CONSTRAINT B_Fk FOREIGN KEY (ref_a, ref_b)
REFERENCES A(a,b) MATCH SIMPLE;
INSERT INTO B(id, ref_a, ref_b) VALUES (1, NULL, 'b');
-- (NULL/'x') 'x' value does not exists in A table, but insert is valid
INSERT INTO B(id, ref_a, ref_b) VALUES (2, NULL, 'x');
ALTER TABLE B DROP CONSTRAINT IF EXISTS B_Fk; -- cleanup
-- MATCH PARTIAL - not implemented
ALTER TABLE B ADD CONSTRAINT B_Fk FOREIGN KEY (ref_a, ref_b)
REFERENCES A(a,b) MATCH PARTIAL;
-- ERROR: MATCH PARTIAL not yet implemented
DELETE FROM B; ALTER TABLE B DROP CONSTRAINT IF EXISTS B_Fk; -- cleanup
-- MATCH FULL nulls are not allowed
ALTER TABLE B ADD CONSTRAINT B_Fk FOREIGN KEY (ref_a, ref_b)
REFERENCES A(a,b) MATCH FULL;
-- FK is defined, inserting NULL as part of FK
INSERT INTO B(id, ref_a, ref_b) VALUES (1, NULL, 'b');
-- ERROR: MATCH FULL does not allow mixing of null and nonnull key values.
-- FK is defined, inserting all NULLs - valid
INSERT INTO B(id, ref_a, ref_b) VALUES (1, NULL, NULL);
答案 10 :(得分:-1)
我认为最好考虑表格中可能的基数。 我们可以有最小基数为零。当它是可选的时,相关表中元组的最小参与可能为零,现在你面临允许外键值为null的必要性。
但答案是这一切都取决于业务。
答案 11 :(得分:-7)
我认为一个表的外键也是其他表的主键。所以它不会允许null。所以外键中没有空值的问题。