这个 table 属于哪个最高范式?

Which highest normal form is this table in?

Ticket Vname Nname
1      Oli   Seitz
1      Andi  Hofmann
2      Oli   Seitz
2      Oli   Schmidt
2      Tim   Schmidt
3      Tim   Hofmann

这个table表示一个人(Vname, Nname)和门票(Ticket)的映射。 VnameNname一起标识一个人,但是每个人(Vname, Nname)可以有多张票(Ticket),一张票可以分配给多人。

这个table的PK都是三列在一起的。所以这个table应该是1NF因为一列没有多维数据

但后来我挣扎了。我认为它是 2NF 和 3NF,因为我找不到任何函数依赖关系。 (希望它们在英语和德语中都被称为函数)

谁能解释一下这个 table 是哪个最高 NF,为什么?我需要更改什么才能在 5NF 中实现?

注意:这不是作业,这个问题来自讨论。

1NF(第一范式)

根据定义,关系每行每列都有一个值,"multi dimensional data in one column" 的概念没有意义。随意问人们有道理。随时问他们他们的意思是什么。

归一化为更高的 NF(正规形式)

更高 NF 的标准化与“1NF”唯一相关的是它们都试图简化以改进设计。

您的关系不满足非平凡的 FD(函数依赖)。所以它在 BCNF.

您的关系不满足非平凡 MVD(多值依赖)。即它不满足非平凡的二进制 JD(连接依赖项)。也就是说,除了包含自身的一对外,它不是任何一对投影的成员的连接。所以它在4NF。你可以通过成对的投影并加入它们来看到这一点。您也可以通过应用 FD 和 MVD 的定义并识别它们,然后为它们应用推理规则来做到这一点。

你的关系满足非平凡的 JD *{{Ticket, Vname}, {Vname, Nname}, {Ticket, Nname}}。所以它是一组投影的成员的连接,而不是包含它自己的集合。但是它的 CK 并不暗示 JD。即没有其投影的连接链,其中每个连接的公共属性都包含原始的 CK。所以它不在5NF中。您可以通过采用多组投影并加入它们来看到这一点。没有算法可以确定一个关系比蛮力更好地满足复杂性的非平凡 JD。

关系Meanings/Predicates

另一方面,假设您知道关系的含义,并且您知道它包含从(特征) predicate 可表示为其他的连词,say

    ticket Ticket was submitted by a person with first name Vname
AND there is a person with name Vname Nname
AND ticket Ticket was submitted by a person with last name Nname

Join 的设计使其输出的谓词是其输入的谓词的 AND。所以你会知道要检查原件的任何相应分解是否满足 JD(即来自合取的关系是否是原件的投影),因此要检查 JD 是否由原件的 CKs 隐含。

更高 NF 规范化的要点是,当关系的谓词可以表示为其他关系的合取并且它们的关系是原始关系的投影时,JD 成立,所以我们可以使用更简单的分离关系,除了我们还不如 JOIN/AND 成对共享 CK 上的 relations/predicates 因为仍然没有更新异常。 (如果FD{x, ...} -> a成立则某个MVD成立&某个二元JD成立,关系的谓词可以表示为... AND a = f(x, ...)。)

请注意,与 5NF 是为了减少更新异常的说法相反,事实证明,它们在 BCNF 和 5NF 之间的 ETNF 中消失了。但是 5NF 设计仍然更简单,因为以向谓词添加 AND 为代价的关系更少。请注意,MVD 和 JD 很难找到 只是因为使用它们的设计在直觉上显然很糟糕,所以它们永远不会被提出,因为它们的谓词是其他谓词的结合。因此,与 5NF 不重要因为违反 JD 的情况很少见的说法相反,5NF 是唯一重要的 NF。 (SQL 系统不支持处理 5NF 设计可能产生的所有完整性约束,因此无知导致人们声称应该接受 3NF。)

您需要找到 NF 的定义 以及它们为何重要

更多关于 predicates & the relational model.

(我才回答这个问题,因为得到的智慧,连教科书上都是这么乱。)


附录

投影和连接。 (我正要离开Minimal, Complete, and Verifiable Example to you. But the JD holding was disputed by another answerer so here is an sqlfiddle。)

T
1      Oli   Seitz
1      Andi  Hofmann
2      Oli   Seitz
2      Oli   Schmidt
2      Tim   Schmidt
3      Tim   Hofmann

project Ticket, Vname (T)
1      Oli
1      Andi
2      Oli
2      Tim
3      Tim

project Vname, Nname (T)
Oli   Seitz
Andi  Hofmann
Oli   Schmidt
Tim   Schmidt
Tim   Hofmann

project Ticket, Vname (T) join project Vname, Nname (T)
1      Oli   Seitz
1      Oli   Schmidt
1      Andi  Hofmann
2      Oli   Seitz
2      Oli   Schmidt
2      Tim   Schmidt
2      Tim   Hofmann
3      Tim   Schmidt
3      Tim   Hofmann

project Ticket, Nname (T)
1      Seitz
1      Hofmann
2      Seitz
2      Schmidt
3      Hofmann

     project Ticket, Vname (T) join project Vname, Nname (T)
join project Ticket, Nname (T)
1      Oli   Seitz
1      Andi  Hofmann
2      Oli   Seitz
2      Oli   Schmidt
2      Tim   Schmidt
3      Tim   Hofmann

谓词是:

[p1] 名为 (FirstName) (LastName) 的人被分配了票号 (Ticket)。

限制条件:

  • (c1.1) 人由名字和姓氏识别。
  • (c1.2) 票由票号识别。
  • (c1.3) 对于每个人,该人可以分配多于一张票。
  • (c1.4) 对于每张票,该票可能分配给一个以上的人。
PersonTicket {FirstName, LastName, Ticket}
         KEY {FirstName, LastName, Ticket}

NF推理:

  1. table是all-key,因此它在BCNF中。
  2. 在BCNF中,无法通过分解来减少冗余,因此在第5个NF中。
  3. 它在第 5 个 NF 和所有键中,因此它在 第 6 个 NF

请注意,关于 NF 的推理不需要任何数据,它必须对空关系变量 (table) 和 table 可能包含的任何可能有效值有效。

还要注意谓词[p1]是一个简单的谓词,它概括了简单的(基本的)事实,这是第 6 个 NF 的标志。例如,事实“Person named Oli Seitz is assigned ticket number 1.” 在不丢失信息的情况下不能拆分成两个句子。


编辑

讨论了很长时间(见评论),所以我必须稍微扩展一下答案。

我的基本前提是table {Ticket, Vname, Nname}不能分解成投影,或者技术上说加入依赖:

JD *{{Ticket, Vname}, {Vname, Nname}, {Ticket, Nname}}

成立。 (注意:Vname = 名字,Nname = 姓氏)。

让我们仔细看看这个。京东持有意味着什么? JD 可以表达为:

IF a person with a first name is assigned a ticket number AND a person with a last name is assigned that ticket number AND there exist a person with that first name and that last name THEN that person with that first name and that last name is assigned that ticket number.

当您第一次读到这篇文章时,可能会感觉不错,一两分钟,但完全错误

看例子:

     Original       |             Three Projections
                    |
(T,  First,  Last ) | (T, First)  (First,   Last )  (T,   Last )
----------------------------------------------------------------- 
(1, 'Tom', '.....') | (1, 'Tom')  ('Tom', '.....')  (1, '.....')
(1, '...', 'Jones') | (1, '...')  ('...', 'Jones')  (1, 'Jones')
(2, 'Tom', 'Jones') | (2, 'Tom')  ('Tom', 'Jones')  (2, 'Jones')

注意元组的连接

(1, 'Tom) ('Tom', 'Jones') (1, 'Jones')

产生一个额外的元组

(1, 'Tom', 'Jones')

原文中没有;因此 JD 不成立

简单地说,一个人的标识符(First, Last)被拆分了。因此,人的名字和姓氏是相互独立的;严重的逻辑错误

看来原题中的样例数据是经过精心雕琢才出现京东持有的; 原来的 data-sample 会通过这个测试。但是,在原来的 table:

中只插入一个元组(行)
(1, 'Tim',  'Seitz')

现在再测试,这个在加入投影时会生成两个额外的元组

(1, 'Tim', 'Hofmann')
(2, 'Tim', 'Seitz')

在推理部分,我使用了如下术语:简单谓词、基本事实、信息、标识符和减少冗余。在下面的评论中,这些被标记为:模糊 non-technical、不合理、错误、含糊、无关紧要和荒谬

有趣的是,这些模糊、含糊、无意义等术语导致了正确的结果,而不是 "precise, highly technical, (algorithm assisted ?)" 方法可能导致 严重的逻辑错误.

所以,对于那些想仔细研究这些——恕我直言,非常有用和实用——术语的人,我可以推荐一些参考资料。

[1]关于简单谓词6th NF:

摄氏度。 J. 日期;数据库设计和关系理论;
第三部分,第十三章,第六范式

[2] 关于基本事实:

特里·哈尔平,托尼·摩根;信息建模和关系数据库;
第 3 章,概念建模:第一步

Terry Halpin,什么是基本事实?,论文 1993。

[3] 关于 5th NF 和减少冗余:

"To say that relvar R is in 5th NF is to say further non loss decomposition of R into projections may be possible, but it won't eliminate any redundancies."

"5NF guarantees freedom from redundancies that can be removed via projection."

C. J. Date; Master Class (video): Database Design and Relational Theory;
Normalization JDs and 5NF (formal)-Part 2 of 2

[4]关于谓词和命题:

第一部分,第 2 章,谓词和命题
第五部分,第 15 章,数据库设计就是谓词设计
在 : C. J. 日期;数据库设计与关系理论。

"Conceptually, the database is a set of sentences expressing propositions taken to be true of the UoD."

Terry Halpin, Tony Morgan; Information Modeling and Relational Databases;
Chapter 2, Information Levels and Frameworks


编辑 2

最后,这里有一些要测试的代码 (PostgreSQL)。

CREATE TABLE tbl_0 (
  Ticket integer  NOT NULL
, Vname  text     NOT NULL
, Nname  text     NOT NULL

, CONSTRAINT pk_tbl PRIMARY KEY (Ticket, Vname, Nname)
);

INSERT INTO tbl_0 (Ticket, Vname, Nname)
VALUES
  (1, 'Oli',  'Seitz')
, (1, 'Andi', 'Hofmann')
, (2, 'Oli',  'Seitz')
, (2, 'Oli',  'Schmidt')
, (2, 'Tim',  'Schmidt')
, (3, 'Tim',  'Hofmann')
;

以下查询生成三个投影,将它们连接在一起并显示原始 table 和连接投影之间的差异。换句话说,确实加入依赖
JD *{{Ticket, Vname}, {Vname, Nname}, {Ticket, Nname}}坚持?

WITH
p_1 AS ( -- projection {Ticket, Vname}
    SELECT DISTINCT Ticket, Vname FROM tbl_0
),
p_2 AS ( -- projection {Vname, Nname}
    SELECT DISTINCT Vname, Nname FROM tbl_0
),
p_3 AS ( -- projection {Ticket, Nname}
    SELECT DISTINCT Ticket, Nname FROM tbl_0
),
j_pro AS ( -- join projections
    SELECT Ticket, Vname, Nname
    FROM p_1
    JOIN p_2 USING (Vname)
    JOIN p_3 USING (Ticket, Nname)
),
d_0 AS ( -- tbl_0 - j_pro
    SELECT Ticket, Vname, Nname FROM tbl_0
    EXCEPT
    SELECT Ticket, Vname, Nname FROM j_pro
),
d_1 AS ( -- j_pro - tbl_0
    SELECT Ticket, Vname, Nname FROM j_pro
    EXCEPT
    SELECT Ticket, Vname, Nname FROM tbl_0
)
-- diff = (tbl_0 - j_pro) union (j_pro - tbl_0)
SELECT Ticket, Vname, Nname FROM d_0
UNION
SELECT Ticket, Vname, Nname FROM d_1

ORDER BY Ticket, Vname, Nname
;

在第一个运行中,一切看起来都还好——似乎JD持有,没有区别:

+--------+-------+---------+
| ticket | vname | nname   |
+--------+-------+---------+

然而,这是一个棘手的问题,该示例经过精心设计以产生此结果。只需再添加一行即可揭示问题所在:

INSERT INTO tbl_0 (Ticket, Vname, Nname)
VALUES (1, 'Tim', 'Seitz');

现在我们得到了两个额外的元组(运行 再次查询)。

+--------+-------+---------+
| ticket | vname | nname   |
+--------+-------+---------+
| 1      | Tim   | Hofmann |
| 2      | Tim   | Seitz   |
+--------+-------+---------+

这里要说清楚的是table和三个投影的连接

-- Added one more row (1, Tim, Seitz)
+--------+-------+---------+
| ticket | vname | nname   |
+--------+-------+---------+
| 1      | Andi  | Hofmann |
| 1      | Oli   | Seitz   |
| 1      | Tim   | Seitz   |
| 2      | Oli   | Schmidt |
| 2      | Oli   | Seitz   |
| 2      | Tim   | Schmidt |
| 3      | Tim   | Hofmann |
+--------+-------+---------+


-- JOIN {{Ticket, Vname}, {Vname, Nname}, {Ticket, Nname}}
-- generates two extra rows
-- (1, Tim, Hoffman) and (2, Tim, Seitz)
+--------+-------+---------+
| ticket | vname | nname   |
+--------+-------+---------+
| 1      | Andi  | Hofmann |
| 1      | Oli   | Seitz   |
| 1      | Tim   | Hofmann |
| 1      | Tim   | Seitz   |
| 2      | Oli   | Schmidt |
| 2      | Oli   | Seitz   |
| 2      | Tim   | Schmidt |
| 2      | Tim   | Seitz   |
| 3      | Tim   | Hofmann |
+--------+-------+---------+

底线,thJD不成立,原来的table {Ticket, Vname, Nname} 不能分解成投影,在6th NF 如本篇第一部分所述——太长现在 -- 回答。


最后的想法

最后,如何确定关系变量的 NF(1NF 中的 table)?通常的答案是:heading、functional dependencies 和 join dependencies。但是标题是来自匹配 predicate 的一组自由变量。依赖关系只是 constraints 的形式化符号。那需要什么呢? Predicate 和匹配的 约束集 ,仅此而已。多少数据,多少行? None,不需要单个元组(行)。最好有少量样本以确保我们正确理解约束,但这不是必需的。专注于样本数据是一个巨大的错误。 Relvar (table) 在特定 NF 中,适用于任何有效元组(行)集,包括空集。如果实施得当,它不应该随着数据不断流入而改变 NF。 NF 是在逻辑设计级别上确定的,在执行 SQL CREATE TABLE 之前。