使用外键进行数据库规范化

时间:2014-09-18 19:11:14

标签: sql sql-server database-normalization

我有一个样本表,如下所示,其中存储了学生的课程完成状态:

Create Table StudentCourseCompletionStatus
(
    CourseCompletionID int primary key identity(1,1),
    StudentID int not null,
    AlgorithmCourseStatus nvarchar(30),
    DatabaseCourseStatus nvarchar(30),
    NetworkingCourseStatus nvarchar(30),
    MathematicsCourseStatus nvarchar(30),
    ProgrammingCourseStatus nvarchar(30)
)
Insert into StudentCourseCompletionStatus Values (1, 'In Progress', 'In Progress', 'Not Started', 'Completed', 'Completed')
Insert into StudentCourseCompletionStatus Values (2, 'Not Started', 'In Progress', 'Not Started', 'Not Applicable', 'Completed')

现在,作为规范化架构的一部分,我创建了另外两个表 - CourseStatusTypeStatus,用于存储课程状态名称和状态。

Create Table CourseStatusType
(
    CourseStatusTypeID int primary key identity(1,1),
    CourseStatusType nvarchar(100) not null
)

Insert into CourseStatusType Values ('AlgorithmCourseStatus')
Insert into CourseStatusType Values ('DatabaseCourseStatus')
Insert into CourseStatusType Values ('NetworkingCourseStatus')
Insert into CourseStatusType Values ('MathematicsCourseStatus')
Insert into CourseStatusType Values ('ProgrammingCourseStatus')
Insert into CourseStatusType Values ('OperatingSystemsCourseStatus')
Insert into CourseStatusType Values ('CompilerCourseStatus')

Create Table Status
(
    StatusID int primary key identity(1,1),
    StatusName nvarchar (100) not null
)

Insert into Status Values ('Completed')
Insert into Status Values ('Not Started')
Insert into Status Values ('In Progress')
Insert into Status Values ('Not Applicable')

修改后的表格如下:

Create Table StudentCourseCompletionStatus1
(
    CourseCompletionID int primary key identity(1,1),
    StudentID int not null,
    CourseStatusTypeID int not null CONSTRAINT [FK_StudentCourseCompletionStatus1_CourseStatusType] FOREIGN KEY (CourseStatusTypeID) REFERENCES dbo.CourseStatusType (CourseStatusTypeID),
    StatusID int not null CONSTRAINT [FK_StudentCourseCompletionStatus1_Status] FOREIGN KEY (StatusID) REFERENCES Status (StatusID),
)

我对此几乎没有疑问:

  1. 这是规范化的正确方法吗?旧表对于轻松获取数据非常有帮助 - 我可以将学生的课程状态存储在一行中,但现在需要5行。有没有更好的方法呢?

  2. 将数据从旧表移动到这个新表似乎不是一件容易的事。我可以使用查询来实现这一点,还是我必须手动执行此操作?

  3. 感谢任何帮助。

3 个答案:

答案 0 :(得分:2)

你还可以考虑将结果存储在平面表中,如下所示:

studentID,courseID,状态

  • 1,1, “已完成”
  • 1,2,“未开始”
  • 2,1,“未开始”
  • 2,3,“正在进行中”

您还需要这样的其他课程表

courserId,courseName

  • 1,数学
  • 2,编程
  • 3,网络

和学生表

  • 1“john smith”
  • 2“perry clam”
  • 3“john deere”

等。你也可以选择创建一个状态表来存储不同的statusstrings状态,并引用他们的PK代替字符串

studentID,courseID,状态

  • 1,1,1
  • 1,2,2-
  • 2,1,2
  • 2,3,3 ......等等。

和状态表

ID,状态

  • 1,“完成”
  • 2,“未开始”
  • 3,“正在进行中”

这种表现形式的美妙之处在于:过滤和汇总数据非常容易,即很容易查询某个人完成了哪些科目,普通学生完成了多少科目,等等。像你一样在柱状设计中更难。您也可以轻松添加新主题,而无需调整您的表格甚至查询它们,只会有效 你也可以随时使用SQLs PIVOT查询来获得熟悉的柱状表示 name,mathstatus,programmingstatus,networkingstatus等。

答案 1 :(得分:1)

  

但现在需要5行

不,它仍然只是一排。该行只包含存储在其他表中的值的标识符。

这有利有弊。以这种方式规范化的主要原因之一是保护数据的完整性。如果列只是一个字符串,那么任何东西都可以存储在那里。但是,如果存在与包含有限值集的表的外键关系,则可以存储其中一个选项。此外,如果您想要更改选项的文本或添加/删除选项,则可以在集中的位置进行。

  

将数据从旧表移动到这个新表似乎不是一件容易的事。

完全没问题。在数据表上创建新的数字列,并使用与每个数据表记录关联的查找表记录的标识符填充它们。如果它们可以为空,你可以立即制作外键。如果它们不可为空,那么您需要填充它们才能使它们成为外键。在您确认数据正确无误后,请删除旧的非规范化列。完成。

答案 2 :(得分:0)

StudentCourseCompletionStatus1中,您仍需要与StatusCourseStatusType建立2个关联。所以我认为你应该考虑遵循规范化的变体:

CourseStatus

这意味着,您的StudentCourseCompletionStatus只会包含一个CourseStatusID,而另一个表CourseStatus会保留与CourseTypeStatus的关联。

要移动数据,您肯定可以使用查询。

相关问题