Question

I have the following (fictitious) tables:

╔════════════════════╗        ╔════════════════════╗
║ 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 ║
╚═══════════╩═════╝

In the Occupation table, there are 2 rows: Student and Teacher.

The B_Occupation_Person binding table allows me to give all the persons an occupation and the B_Course_Person binding table allows me to associate a teacher with a course.

My problem is I'd like to ensure that B_Course_Person could only contain teachers.

My first idea was to add a check constraint on this table but I can only do it by using a UDF to get the person's occupation from the B_Occupation_Person table. And from what I read here, it's bad to use a UDF in a check constraint.

My second idea was to add a column Occupation in the B_Course_Person table but then I get data redundancy...

What's the best way, here?

Thanks,

Was it helpful?

Solution

If you have a "type" column in your person table to distinguish students from teachers (which is e.g. not possible if a person can be both) you can include that type column in the primary key, and then restrict the foreign key the link table to teachers:

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')
);

The person_type is redundant in the b_occupation_person but as far as I can tell it's the only option to create this type of constraint in a declarative manner.

Due to the foreign key and the check constraint it's not possible to insert anything else but a teacher into b_occupation_person.

But again: this only works if you actually can distinguish teachers from students (and if a teacher cannot be a student).

If you need a person to be teacher and student (and you don't have a "person_type"), you might think about a teacher table that simply references the person table:

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)
);

The drawback of this is that a person that is teacher needs to be inserted twice (once into person, once into teacher).

In PostgreSQL you could take advantage of table inheritance and define teacher to inherit from person. Thus any insert into teacher would automatically create a person as well (so you don't need to insert such a person twice).

OTHER TIPS

Your question here represents a form of business logic. You not only have the issue of making sure that b_course_person only contains teachers at the time of insertion, but also that the data remains consistent - ie: if a person stops becoming a teacher, what happens to the data in b_course_person then?

As such, you should implement this logic in code; either as a stored procedure that represents your interface to the database and ensures that all data changes result in a consistent, valid set of data, or further up the layers of your application in a business logic layer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top