为什么我的SQL表不是正常形式

时间:2014-01-14 15:16:26

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

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

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

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

2 个答案:

答案 0 :(得分:1)

回答这个问题。

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

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

根据您打算如何使用数据,第3次正常可能不是存储数据的最有效方式。

答案 1 :(得分:1)

根据您的编辑 - 关闭,但我会转过来。我将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])
) 

然后反转外键。

如果地址需要校正,那么只需要在一行中进行校正 - 这是在所有标准化点之后 - 只需要应用一次校正。