在考虑1NF失败时,没有重复的元素组,如果您想对重复组的数量设置限制,该怎么办?
例如,您希望学生只列出3个电话号码。不再。如果有一个表如下被认为是1NF失败?
Student 1 Phone1 Phone2 Phone3
Sally 111-1111 222-2222 333-3333
John 555-5555 999-9999 NULL
您将创建一个限制。这是否可接受,高效的数据库设计?
将电话号码放在单独的表中是否会更好,因为1NF故障需要?如果它位于单独的表中,您将如何为每个用户创建3个数字的限制?
答案 0 :(得分:7)
不,它没有正常化。当存在空值时,您将在表中浪费空间,如果要执行搜索特定电话号码等操作,则必须搜索所有三列。而是使用一个单独的表(例如,StudentPhoneNumbers)来存储它们。如果您想将其限制为三个,请使用触发器来防止每个学生超过三个。
答案 1 :(得分:6)
1NF连续禁止重复列表。您的设计违反了这一点,以下设计也是如此:
Student Phones
'John D' '555-5555, 666-6666, 777-7777'
'Sally S' '111-1111, 222-2222'
以下设计会违反2NF,因为唯一的主键是Name, Phone
,但Address
属性不依赖于Phone
:
Name Phone Address
'John D' '555-5555' '1 Square Village'
'John D' '666-6666' '1 Square Village'
'John D' '777-7777' '1 Square Village'
'Sally S' '111-1111' '999 Flash City'
'Sally S' '222-2222' '999 Flash City'
下一个设计会违反3NF,因为AreaName不依赖于Name,而只依赖于Area:
Name Area Phone AreaName
'John D' '555' '5555' '111name'
'John D' '666' '6666' '666name'
'John D' '777' '7777' '777name'
'Sally S' '111' '1111' '111name'
'Sally S' '222' '2222' '222name'
即使您的设计违反1NF,它也是一个很好的选择。添加PhoneNumber
表的复杂性几乎没有道理。
如果您遵守1NF,请考虑对客户的更新有多难。这些数字将在一个单独的表格中。因此,如果有人提交了一份包含更新电话号码列表的表单,您将如何更改数据库?首先,您必须检索现有的数字列表。然后你必须将它们与提交的列表进行比较。然后,您必须根据差异删除或插入行。一个复杂的解决方案。
如果坚持使用您的解决方案,您只需更新三列即可。节省的时间可以花在真实的功能上!甚至在Stack Overflow上写下长答案。
答案 2 :(得分:3)
您的关系变量(relvar)确实违反了1NF,但可能不是因为您期望的原因:存在违反1NF的空值。如果您认为您的relvar包含重复组,请再想一想。
第一范式,或简单地"标准化",是关系模型的最低要求。引用Chris Date:
根据定义,null不是一个值。由此得出:A"类型"那 包含null isn&a;是一个类型(因为类型包含值); A"元组" 包含null isn&t; tuple(因为元组包含值);一个 "关系"包含null不是关系(因为关系 包含元组,而元组不包含空值。实际上,空值 违反了最基本的关系原则 - 即 信息原理。所有这一切的网络是,如果为空 现在,我们肯定不会谈论关系模型 (我不知道我们在谈论什么,但它不是关系型的 模型);整个大厦都崩溃了,所有的赌注都没了。
关于重复小组和1NF的观点是一个难以解释的问题,我不会尝试。相反,我恳请您阅读Facts and Fallacies about First Normal Form,特别是“重复群体的歧义”#34;
假设null被消除,relvar将满足1NF,但请注意我们需要更多信息(例如键)来确定它是否也满足更高的正常形式。
答案 3 :(得分:1)
user1122200,让我们假设你的数据库设计在增长。而且您需要为每个电话号码分配特定数据(例如电话位置:'house','work',...)。在这种情况下,你会渴望一个电话桌。此外,你需要从电话号码中找到学生(比如有人打电话时的披萨小屋或出租车服务),这个查询更容易在规范化设计中查询:
select *
from students
where
Phone1 = '91112223' or
Phone2 = '91112223' or
Phone3 = '91112223'
答案 4 :(得分:1)
如果每个用户位于单独的表中,您将如何创建3个数字的限制?
我假设学生可能有零个,一个两个或三个电话号码。
如果您的SQL产品支持Full SQL-92:
CREATE TABLE Students
(
student_name VARCHAR(20) NOT NULL UNIQUE
);
CREATE TABLE StudentPhonebook
(
student_name VARCHAR(20) NOT NULL
REFERENCES Students (student_name),
phone_number CHAR(8) NOT NULL
CHECK (phone_number LIKE '[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'),
UNIQUE (student_name, phone_number)
);
CREATE ASSERTION students_max_three_phone_numbers
CHECK (
NOT EXISTS (
SELECT *
FROM (
SELECT student_name, COUNT(*) AS tally
FROM StudentPhonebook
GROUP
BY student_name
) AS DT1
WHERE tally > 3
)
);
MySQL不支持任何风格的CHECK
,并且没有SQL产品支持CREATE ASSERTION
所以上述约束必须使用过程代码编写,例如触发器。
出于兴趣,如果您的SQL产品支持行级CHECK
约束(大多数情况下),可以使用带有occurrence
约束的BETWEEN 1 AND 3
属性,然后将此属性包括在内关键约束,例如
CREATE TABLE StudentPhonebook
(
student_name VARCHAR(20) NOT NULL
REFERENCES Students (student_name),
phone_number CHAR(8) NOT NULL
CHECK (phone_number LIKE '[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'),
occurrence INTEGER DEFAULT 1 NOT NULL
CHECK (occurrence BETWEEN 1 AND 3),
UNIQUE (student_name, phone_number),
UNIQUE (student_name, occurrence)
);