请为我澄清两件事:
外键可以为NULL吗?外键可以重复吗?
据我所知,NULL
不应该用于外键,但在我的某些应用程序中,我可以在 Oracle 和 SQL Server 中输入 NULL
,但我不知道为什么。
简短回答:是的,它可以为 NULL 或重复。
我想解释为什么外键可能需要为空或可能需要唯一或不唯一。首先记住外键只要求该字段中的值必须首先存在于不同的表(父表)中。这就是 FK 的定义。根据定义,Null 不是一个值。 Null 意味着我们还不知道值是什么。
让我给你一个现实生活中的例子。假设您有一个存储销售建议的数据库。进一步假设每个提案只分配了一个销售人员和一个客户。因此,您的提案表将有两个外键,一个带有客户 ID,一个带有销售代表 ID。但是,在创建记录时,并不总是分配销售代表(因为还没有人可以自由地处理它),因此填写了客户 ID,但销售代表 ID 可能为空。换句话说,当您在输入数据时可能不知道它的值,但您确实知道表中需要输入的其他值时,通常您需要具有空 FK 的能力。通常,要在 FK 中允许空值,您所要做的就是在具有 FK 的字段上允许空值。空值与它是 FK 的想法是分开的。
是否唯一与表与父表是一对一还是一对多的关系有关。现在,如果您有一对一的关系,您可以将数据全部放在一个表中,但是如果表变得太宽或者数据是关于不同的主题(员工 - 保险示例 @tbone 给出例如),那么您需要带有 FK 的单独表。然后,您可能希望将此 FK 也设为 PK(保证唯一性)或对其施加唯一约束。
大多数 FK 是针对一对多关系的,这就是您从 FK 获得的,而无需在字段上添加进一步的约束。例如,您有一个订单表和订单详细信息表。如果客户一次订购十件商品,则他有一份订单和十份订单明细记录,其中包含与 FK 相同的 orderID。
从马口中:
即使没有匹配的 PRIMARY 或 UNIQUE 键,外键也允许键值全部为 NULL核心价值。此模型允许在外键中使用空值。 ... 外键上的 NOT NULL 约束 当外键中不允许空值时,子表中的每一行都必须显式引用父键中的值,因为外键中不允许空值。子表中任意数量的行都可以引用相同的父键值,因此该模型在父键和外键之间建立了一对多的关系。但是,子表中的每一行都必须引用一个父键值;不允许外键中没有值(null)。上一节中的相同示例可用于说明这种关系。但是,在这种情况下,员工必须具有对特定部门的引用。外键上的 UNIQUE 约束 当外键上定义了 UNIQUE 约束时,子表中只有一行可以引用给定的父键值。此模型允许在外键中使用空值。此模型在父键和外键之间建立一对一的关系,允许外键中存在未确定的值(空值)。例如,假设员工表有一个名为 MEMBERNO 的列,指的是公司保险计划中的员工会员编号。此外,名为 INSURANCE 的表有一个名为 MEMBERNO 的主键,该表的其他列保存与员工保险单相关的相应信息。员工表中的 MEMBERNO 必须既是外键又是唯一键: 强制执行 EMP_TAB 和 INSURANCE 表之间的参照完整性规则(FOREIGN KEY 约束) 保证每个员工都有唯一的成员编号(UNIQUE 键约束)外键上的 UNIQUE 和 NOT NULL 约束当在外键上同时定义 UNIQUE 和 NOT NULL 约束时,子表中只有一行可以引用给定的父键值,并且由于外键中不允许 NULL 值,子表中的每一行都必须显式引用父键中的值。
看到这个:
1 - Yes, since at least SQL Server 2000.
2 - 是的,只要它不是 UNIQUE
约束或链接到唯一索引。
是的,正如高级程序员所说,外键可以为空......我会添加另一个场景,外键需要为空......假设我们在应用程序中有表格评论、图片和视频,它允许对图片和视频进行评论视频。在评论表中,我们可以有两个外键 PicturesId 和 VideosId 以及主键 CommentId。因此,当您对视频发表评论时,仅需要 VideosId 且 pictureId 将为空...如果您对图片发表评论,则仅需要 PictureId 而 VideosId 将为空...
这取决于此 foreign key
在您的关系中扮演的角色。
如果这个外键也是你关系中的一个键属性,那么它不能为 NULL 如果这个外键是你关系中的一个普通属性,那么它可以是 NULL。
key attribute
是什么意思?
下面是一个使用 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 表中。
默认情况下,外键没有限制,外键可以为空和重复。
在创建表/更改表时,如果您添加任何唯一性约束或非空值,那么只有它不允许空值/重复值。
简而言之,实体之间的“非识别”关系是 ER-Model 的一部分,在设计 ER-Diagram 时可在 Microsoft Visio 中使用。这是在“零或大于零”或“零或一”类型的实体之间强制执行基数所必需的。请注意基数中的“零”而不是“一对多”中的“一”。
现在,基数可能为“零”(非识别)的非识别关系的示例是当我们说一个实体中的记录/对象时-“可能”或“可能不”具有作为对记录的引用的值/s 在另一个实体-B 中。
因为,实体-A 的一个记录有可能将自己标识为其他实体-B 的记录,因此实体-B 中应该有一列具有实体-B 记录的标识值。如果实体 A 中没有记录标识实体 B 中的记录(或对象),则此列可能为“空”。
在面向对象(现实世界)范式中,存在 B 类对象的存在不一定依赖于(强耦合)A 类对象的情况,这意味着 B 类与与 B 类对象的概念相反,A 类可以“包含”(包含)A 类对象的一个对象必须具有(组合)A 类对象,因为它的(类对象- B) 创造。
从 SQL 查询的角度来看,您可以查询实体 B 中为实体 B 保留的外键“非空”的所有记录。这将为实体 A 中的行带来具有特定相应值的所有记录,或者所有具有 Null 值的记录将是在实体 B 中的实体 A 中没有任何记录的记录。
外键可以为NULL吗?
现有答案侧重于单列方案。如果我们考虑多列外键,我们有更多使用 SQL 标准中定义的 MATCH [SIMPLE | PARTIAL | FULL]
子句的选项:
PostgreSQL-CREATE TABLE 插入引用列的值与使用给定匹配类型的被引用表和被引用列的值匹配。共有三种匹配类型:MATCH FULL、MATCH PARTIAL 和 MATCH SIMPLE(这是默认设置)。 MATCH FULL 将不允许多列外键的一列为空,除非所有外键列都为空;如果它们都为空,则该行不需要在引用的表中具有匹配项。 MATCH SIMPLE 允许任何外键列为空;如果其中任何一个为空,则该行不需要在引用的表中具有匹配项。 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);
我认为最好考虑表中可能存在的基数。我们可以有可能的最小基数为零。当它是可选的时,相关表中元组的最小参与可能为零,现在您面临着外键值被允许为空的必要性。
但答案是这一切都取决于业务。
外键的概念是基于引用主表中已经存在的值的概念。这就是为什么它在另一个表中被称为外键。这个概念称为参照完整性。如果将外键声明为空字段,它将违反引用完整性的逻辑。它指的是什么?它只能引用主表中存在的东西。因此,我认为将外键字段声明为 null 是错误的。
NULL
,但参照完整性的意思是,如果它引用“某物”,它必须在那里。
我认为一个表的外键也是其他表的主键。所以它不允许空值。所以外键中没有空值的问题。
NULL
换取了另一个表中的多个NULL
。