我有以下(虚构)表:
╔════════════════════╗ ╔════════════════════╗
║ Course ║ ║ Person ║
╠══════╦═════════════╣ ╠══════╦═════════════╣
║ ID ║ int ║ ║ ID ║ int ║
║ Name ║ varchar(50) ║ ║ Name ║ varchar(50) ║
╚══════╩═════════════╝ ╚══════╩═════════════╝
╔════════════════════╗ ╔═════════════════════╗
║ Occupation ║ ║ B_Occupation_Person ║
╠══════╦═════════════╣ ╠══════════════╦══════╣
║ ID ║ int ║ ║ Person_ID ║ int ║
║ Name ║ varchar(50) ║ ║ Ocupation_ID ║ int ║
╚══════╩═════════════╝ ╚══════════════╩══════╝
╔═════════════════╗
║ B_Course_Person ║
╠═══════════╦═════╣
║ Course_ID ║ int ║
║ Person_ID ║ int ║
╚═══════════╩═════╝
在Occupation
表中,共有2行:Student
和Teacher
。
B_Occupation_Person
绑定表允许我为所有人提供职业,B_Course_Person
绑定表允许我将教师与课程相关联。
我的问题是我想确保B_Course_Person
只能包含教师。
我的第一个想法是在此表上添加一个检查约束,但我只能通过使用UDF从B_Occupation_Person
表中获取该人的职业来实现。从我读到的here开始,在检查约束中使用UDF是不好的。
我的第二个想法是在Occupation
表中添加一列B_Course_Person
,但后来我获得了数据冗余......
这里最好的方法是什么?
谢谢,
答案 0 :(得分:1)
如果您的人员表中有一个“类型”列,以区分学生和教师(例如,如果一个人可以同时这两个人就不可能),您可以在主键中包含该类型列,然后限制外键教师的链接表:
create table person
(
id integer not null,
person_type varchar(10) not null,
name varchar(100),
constraint pk_person primary key (id, person_type),
constraint type_check check (person_type in ('student', 'teacher'))
);
create table b_occupation_person
(
occupation_id integer not null,
person_id integer not null,
person_type varchar(10) not null,
constraint fk_occupation_person
foreign key (person_id, person_type)
references person (id, person_type),
constraint type_check check (person_type = 'teacher')
);
person_type
中的b_occupation_person
是多余的,但据我所知,它是以声明方式创建此类约束的唯一选项。
由于外键和检查约束,除了教师之外,不能将任何其他内容插入b_occupation_person
。
但是又一次:这只有在你真正可以区分教师与学生(以及教师不能成为学生)的情况下才有效。
如果您需要一个人成为教师和学生(并且您没有“person_type”),您可能会想到一个只引用人员表的teacher
表:
create table person
(
id integer not null primary key,
name varchar(100)
);
create table teacher
(
person_id integer not null primary key,
foreign key (person_id) references person (id)
);
create table b_occupation_person
(
occupation_id integer not null,
teacher_id integer not null,
foreign key (teacher_id) references teacher (person_id)
);
缺点是教师需要插入两次(一次进入人,一次进入教师)。
在PostgreSQL中,您可以利用表继承并定义教师继承人。因此,任何插入教师的内容都会自动创建一个人(所以你不需要两次插入这样的人)。
答案 1 :(得分:0)
这里的问题代表了一种业务逻辑。您不仅要确保b_course_person在插入时仅包含教师,而且数据保持一致 - 即:如果某人不再成为教师,那么b_course_person中的数据会发生什么?
因此,您应该在代码中实现此逻辑;或者作为表示数据库接口的存储过程,并确保所有数据更改都会生成一致,有效的数据集,或者进一步提升业务逻辑层中应用程序的各个层。