没有UDF的SQL检查约束

时间:2012-08-27 16:51:06

标签: sql user-defined-functions data-integrity check-constraint

我有以下(虚构)表:

╔════════════════════╗        ╔════════════════════╗
║ 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行:StudentTeacher

B_Occupation_Person绑定表允许我为所有人提供职业,B_Course_Person绑定表允许我将教师与课程相关联。

我的问题是我想确保B_Course_Person只能包含教师。

我的第一个想法是在此表上添加一个检查约束,但我只能通过使用UDF从B_Occupation_Person表中获取该人的职业来实现。从我读到的here开始,在检查约束中使用UDF是不好的。

我的第二个想法是在Occupation表中添加一列B_Course_Person,但后来我获得了数据冗余......

这里最好的方法是什么?

谢谢,

2 个答案:

答案 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中的数据会发生什么?

因此,您应该在代码中实现此逻辑;或者作为表示数据库接口的存储过程,并确保所有数据更改都会生成一致,有效的数据集,或者进一步提升业务逻辑层中应用程序的各个层。