【问题标题】:Why is my SQL table not in 3 normal form为什么我的 SQL 表不是 3 范式
【发布时间】:2014-02-02 17:15:53
【问题描述】:

我已经制作了这个数据库。看起来它工作正常,除了我被告知我的表“事件”不是第三范式。我不明白为什么它不是第三范式。我认为这可能是因为城市和邮政编码应该总是相同的,但是大城市可以有多个邮政编码,我没有看到为城市及其邮政编码创建另一个表的意义,相关到事件表。

如果使用系统保留的某些名称错误地命名了某些名称或属性,也很抱歉。我不得不把代码翻译成英文,因为我是用我的母语写的:)。感谢您的帮助。

Create table [article]
(
    [id_article] Integer Identity(1,1) NOT NULL,
    [id_author] Integer NOT NULL,
    [id_category] Integer NOT NULL,
    [title] Nvarchar(50) NOT NULL,
    [content] Text NOT NULL,
    [date] Datetime NOT NULL,
Primary Key ([id_article])
) 
go

Create table [author]
(
    [id_author] Integer Identity(1,1) NOT NULL,
    [name] Nvarchar(25) NOT NULL,
    [lastname] Nvarchar(25) NOT NULL,
    [email] Nvarchar(50) NOT NULL, UNIQUE ([email]),
    [phone] Integer NOT NULL, UNIQUE ([phone]),
    [nick] Nvarchar(20) NOT NULL, UNIQUE ([nick]),
    [passwd] Nvarchar(50) NOT NULL,
    [acc_number] Integer NOT NULL, UNIQUE ([acc_number]),
Primary Key ([id_author])
) 
go

Create table [event]
(
    [id_event] Integer Identity(1,1) NOT NULL,
    [id_author] Integer NOT NULL,
    [name] Nvarchar(50) NOT NULL,
    [date] Datetime NOT NULL, UNIQUE ([date]),
    [city] Nvarchar(50) NOT NULL,
    [street] Nvarchar(50) NOT NULL,
    [zip] Integer NOT NULL,
    [house_number] Integer NOT NULL,
    [number_registered] Integer Default 0 NOT NULL Constraint [number_registered] Check (number_registered <= 20),
Primary Key ([id_event])
) 
go

Create table [user]
(
    [id_user] Integer Identity(1,1) NOT NULL,
    [name] Nvarchar(15) NOT NULL,
    [lastname] Nvarchar(25) NOT NULL,
    [email] Nvarchar(50) NOT NULL, UNIQUE ([email]),
    [phone] Integer NOT NULL, UNIQUE ([phone]),
    [passwd] Nvarchar(50) NOT NULL,
    [nick] Nvarchar(20) NOT NULL, UNIQUE ([nick]),
Primary Key ([id_user])
) 
go

Create table [commentary]
(
    [id_commentary] Integer Identity(1,1) NOT NULL,
    [content] Text NOT NULL,
    [id_article] Integer NOT NULL,
    [id_author] Integer NULL,
    [id_user] Integer NULL,
Primary Key ([id_commentary])
) 
go

Create table [category]
(
    [id_category] Integer Identity(1,1) NOT NULL,
    [name] Nvarchar(30) NOT NULL,
Primary Key ([id_category])
) 
go

Create table [registration]
(
    [id_user] Integer NOT NULL,
    [id_event] Integer NOT NULL,
Primary Key ([id_user],[id_event])
) 
go


Alter table [commentary] add  foreign key([id_article]) references [article] ([id_article])  on update no action on delete no action 
go
Alter table [article] add  foreign key([id_author]) references [author] ([id_author])  on update no action on delete no action 
go
Alter table [event] add  foreign key([id_author]) references [author] ([id_author])  on update no action on delete no action 
go
Alter table [commentary] add  foreign key([id_author]) references [author] ([id_author])  on update no action on delete no action 
go
Alter table [registration] add  foreign key([id_event]) references [event] ([id_event])  on update no action on delete no action 
go
Alter table [commentary] add  foreign key([id_user]) references [user] ([id_user])  on update no action on delete no action 
go
Alter table [registration] add  foreign key([id_user]) references [user] ([id_user])  on update no action on delete no action 
go
Alter table [article] add  foreign key([id_category]) references [category] ([id_category])  on update no action on delete no action 
go

编辑: 你认为它可以这样工作吗?我创建了另一个名为 location 的表,其中包含以前在事件表中的所有地址信息,并创建了 id_event PFK。

Create table [event]
(
    [id_event] Integer Identity(1,1) NOT NULL,
    [id_author] Integer NOT NULL,
    [name] Nvarchar(50) NOT NULL,
    [datr] Datetime NOT NULL,
    [number_registered] Integer Default 0 NOT NULL Constraint [number_registered] Check (number_registered <= 20),
Primary Key ([id_event])
) 
go


Create table [location]
(
    [city] Char(1) NOT NULL,
    [id_event] Integer NOT NULL,
    [street] Char(1) NOT NULL,
    [house_number] Char(1) NOT NULL,
    [zip] Char(1) NOT NULL,
Primary Key ([id_event])
) 
go


Alter table [event] add  foreign key([id_auhtor]) references [author] ([id_author])  on update no action on delete no action 
go

Alter table [location] add  foreign key([id_event]) references [event] ([id_event])  on update no action on delete no action 
go

【问题讨论】:

  • 我会说审阅者是正确的,但不是...毕竟您没有用于邮政编码、城市和街道的不同表格。然而……你愿意吗?完美的标准化并不总是“正确”的方式。
  • 两个事件可以在同一个地址发生吗?如果是这样,我会认为分隔应该是所有地址列到一个单独的表中。但是,一般来说,您无法仅通过查看表定义来确定表是否为第三范式。它们是否存在取决于实际的数据
  • @Liath:如果不在 3NF 中,则必须存在传递依赖。它在哪里?

标签: sql sql-server normalization database-normalization third-normal-form


【解决方案1】:

回答问题。

你是对的,数据库不是第三范式。如您所见,有机会规范化各种邮政编码、城市和街道。这将导致每个邮政编码(等)都有一行,并且每个邮政编码都有 FK。

就我个人而言,我不这样做。这显然取决于应用程序,但在我的系统中,我更感兴趣的是获取用户的地址,而不是所有具有特定邮政编码的用户。

根据您打算如何使用数据,第三法线可能不是存储数据的最有效方式。

【讨论】:

  • 好的,假设我们创建了一个包含邮政编码列的邮政编码表。进一步说,我们决定成为关系纯粹主义者并为该表使用自然主键 - 邮政编码是唯一的,所以我们将使用它。现在,event 表中的外键将是……邮政编码。我认为您没有通过将邮政编码移到单独的表中来实现任何形式的规范化。
  • 一个很好的观点 - 就我个人而言,我认为你所能希望实现的就是使用 ID 键来最小化一些索引的大小......但我认为你会让数据更难查询和复杂的缘故。
  • 我编辑了我的帖子,并尝试使其正确。你怎么看待这件事?你认为它会起作用并满足第三范式吗?
  • 就我个人而言,我认为您的第一次尝试更好——第 3 范式在很多时候是一个很好的指南,但并非在所有情况下——您实际上并没有告诉我们您的应用程序是做什么的,所以很难建议在这种情况下它是否是最好的设计。
  • 这是一个内容管理系统,作者可以在其中撰写各种文章,用户可以阅读它们,但作者可以像在 Facebook 上一样制作活动。我希望他们能够创建一个事件,为其命名并设置时间和位置。如果他们想去那里,用户可以自己注册。但是,这不是我会实际使用的东西。我正在学习如何制作正确的数据库,这是我得到的任务,事件表是我被告知的唯一不完全正确的东西。
【解决方案2】:

根据您的编辑 - 关闭,但我会扭转它。我会给location 一个location_id 列(PK),删除它的event_id 列,然后使event 成为:

Create table [event]
(
    [id_event] Integer Identity(1,1) NOT NULL,
    [id_author] Integer NOT NULL,
    id_location Integer NOT NULL, /* Or null? does every event have to have a location */
    [name] Nvarchar(50) NOT NULL,
    [datr] Datetime NOT NULL,
    [number_registered] Integer Default 0 NOT NULL Constraint [number_registered] Check (number_registered <= 20),
Primary Key ([id_event])
) 

然后也反转外键。

这样,如果一个地址需要更正,它只需要在一行中进行更正 - 毕竟这是标准化的一点 - 只需应用一次更正。

【讨论】:

  • @Arcane - 是的,这就是我所期望的(考虑到我希望出现在这些名称的表格中的虚构数据 - 正如我在对你的问题的最初评论中所说的那样,它是实际上不可能知道表是否被规范化而不实际知道数据的样子和实际的预期用途)
  • 好的,作者将如何使用 INSERT 脚本添加事件?他会在 id_location 中输入什么?我以为如果是在我这样的弱实体中,他也必须输入地址,但现在似乎不像。
  • 可以引入id,但是跟规范化没有关系。
猜你喜欢
  • 2016-12-24
  • 2021-10-22
  • 2012-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多