规范化表数据

时间:2015-04-10 04:21:24

标签: sql database-normalization

目前,我对我的表和关系进行了此设置:

diagram

情况:

有些员工参加课程。他们在名单上签名,这是该课程独有的。这些课程可以由不同的教师多次教授。每门课程可能有不同学生的多个名册(不同课程的不同名册)。还有其他规格,但在大多数情况下,员工/教师表是我关心的。

我的问题是,可能存在教师也是雇员的情况。两个表之间的唯一区别是使用InstructorID而不是EmployeeID。这会为我的数据创建一些冗余。我想避免这种情况,并尝试根据最佳实践来构建它。有没有办法将两个表中的数据组合在一起,以便在任何时候,我可以查询所有教授某些员工课程的教师的表格?

我想到了在Employees表中添加Yes / No的“isInstructor”字段。然后,我可以检查一个人是否有。但是,我觉得这是一个可怕的想法。有人建议在employeeID中添加一个前缀,以指定他们是一名教师。还有人建议,也许我会添加一个额外的字段,其中包含也是员工的教师的标识符。

基本上,我想知道这个问题的最佳实践方法是什么。我应该将数据分开并分成两个表格,还是应该将它们组合起来并添加内容?对结构的其余部分的任何建议也受到赞赏。这是我在这里的第一个问题,所以如果需要更多细节,请告诉我。

2 个答案:

答案 0 :(得分:0)

我会从Instructors {删除Department移除Instructors->DeptID并将EmployeeID作为外键放入Instructors。所以没有EmployeeID的教师(实际上是null ID)是外部教练。

这仍然会使Instructors处于非规范化状态,但应该足以满足您的目的。

答案 1 :(得分:0)

教师和员工都是人。 (我故意使用varchar(5),所以你不能在生产中使用它,至少出现来考虑名字。)

create table people (
  p_id integer primary key,
  first_name varchar(5) not null,
  last_name varchar(5) not null,
  dept_id integer not null references departments
);

insert into people values
(1, 'Robin', 'Mings', 1),
(2, 'Ora', 'Black', 1),
(3, 'Sheri', 'Johns', 2),
(4, 'Dex', 'Sims', 3);

最佳实践:如果要对表名使用复数,则始终使用复数。如果您想使用单面信息表格,请始终使用单面。 (我使用复数。)

使用表格捕获有关某人是否受雇以及某人是否为教师的详细信息。至少你需要知道的是他们的身份证号码。 Robin Mings和Sheri Johns是教练。

create table instructors (
  p_id integer primary key references people
);

insert into instructors values 
(1), (3);
教练Sheri Johns不是雇员。但其他人都是。

create table employees (
  p_id integer primary key references people
);

insert into employees values
(1), (2), (4);

在“雇员”和“教师”表中,使用“p_id”(“人员”中的列名称)或“emp_id”等列名称的选择取决于应用程序。

  

这些课程可以由不同的教师多次教授。

不,他们不能。您的设计每个课程只允许一个日期。区分课程和课程。课程是在特定教师的指导下开设的课程,它从特定的日期开始。

create table courses (
  course_id integer primary key,
  course_name varchar(5) not null unique,
  course_desc varchar(5) not null,       -- unique?
  course_objectives varchar(5) not null  -- Think about whether this deserves its own table.
);

insert into courses values
(1, 'AP101', 'Desc', 'Obj'),
(2, 'AR101', 'Desc', 'Obj');

最佳实践:请勿在表名中使用 list 等字词。没有人说,“你应该参加这个课吗?让我查看我的名单。”此外,语义计数。如果您使用“roster_list”和“course_list”(在您的情况下实际上不是课程或名单的列表),为什么不使用“employee_list”,“department_list”等? List 只是噪音。选择更好的词语。

create table classes (
  course_id integer not null references courses,
  instructor_id integer not null references instructors (p_id),
  start_date date not null,
  -- I have no idea what completion_time means, so I omitted it.
  primary key (course_id, instructor_id, start_date)
);

insert into classes values
(1, 1, '2015-04-01'),
(2, 3, '2015-04-15');

根据我的经验,员工报名参加课程,而不是课程。 (您使用了 sessions 这个词,但在您的设计中没有使用它。)根据应用程序的不同,您可能需要比此更多的表。

create table class_rosters (
  course_id integer not null,
  instructor_id integer not null,
  start_date date not null,
  employee_id integer not null references employees (p_id)
    on update restrict on delete cascade,
  primary key (course_id, instructor_id, start_date, employee_id),
  foreign key (course_id, instructor_id, start_date)
    references classes (course_id, instructor_id, start_date) 
    on update cascade on delete cascade
);

insert into class_rosters values 
(1, 1, '2015-04-01', 2),
(1, 1, '2015-04-01', 4),
(2, 3, '2015-04-15', 1), -- An instructor is taking this class.
(2, 3, '2015-04-15', 2),
(2, 3, '2015-04-15', 4);
  

有没有办法将两个表中的数据组合在一起   点,我可以查询所有教授课程的教师的表格   某些员工?

-- Instructors who teach a class that has Ora Black in it.
select distinct cr.instructor_id
from class_rosters cr
inner join people p on p.p_id = cr.employee_id
where p.first_name = 'Ora' and p.last_name = 'Black';

-- Instructors who teach a class that has both Ora Black 
-- and Robin Mings (an instructor) in it.
with students as (
  select p_id 
  from people
  where (first_name = 'Ora' and last_name = 'Black')
     or (first_name = 'Robin' and last_name = 'Mings')
)
select instructor_id
from class_rosters cr
inner join students s on s.p_id = cr.employee_id
group by course_id, instructor_id, start_date
having count(*) = (select count(*) from students);
instructor_id
--
3