简体   繁体   中英

How to implement total disjoint specialization in database?

Say there is a database for students and professors (a very simple one) and the relational database is the following:

GradStudent (_id_, name, gradStuff)
UndergradStudent (_id_, name, underGradStuff)
Professor (_id_, name)
Teaches(_prof_id_, _stud_id_)

Considering that the relational database above is meant to represent total disjoint specialization, ie there is no table Student but rather two completely seperate ones, when writing this in SQL in order to implement the database, how would I fetch the student id for the Teaches table? I cannot figure out how to make a foreign key from two different tables.

I am writing this question assuming that the SQL language is not all the different across all the platforms. If clarification is needed: I am working on Oracle SQL Developer.

Edit :: additional info / Clarification:

For a more graphical, simplistic view on what I am trying to achieve:

I want to write the following in SQL code (however I do not know how is it possible and thus don't know how to)

在此处输入图像描述

My apologies if the picture is too simplistic, if needed I can add more attributes and details, just let me know.

If by "fetch the student id for the Teaches table", you mean you want Teaches.stud_id to be a FK that references "GradStudent or Undergradstudent as is the case", you can't. The target of a FK must be a key of a table that is not a view. You have no such table, ergo you have no such key either.

Only way I see is to code a trigger that does the check upon inserts/updates to Teaches.

I cannot figure out how to make a foreign key from two different tables.

You mean, a foreign key to/referencing two different tables. But there is no such foreign key in this design.

We declare an SQL FOREIGN KEY for a table to say that (ie to tell the DBMS that) the values for a list of columns are also values of a list of corresponding columns (maybe the same list) that are unique in a table (maybe the same table). You don't have this here. You have a different constraint on your tables.

If you want exactly those base tables then you have to use triggers in SQL to enforce your constraints.

You can also have a design with:

  • base table Student with NOT NULL UNIQUE or PRIMARY KEY id
  • FOREIGN KEYs from GradStudent (id), UndergradStudent (id) and Teaches (stud_id) REFERENCES Student (id)
  • a constraint that the projection of Student on id is the disjoint union of the projections of GradStudent and UndergradStudent on id

You could express part the latter constraint by a trigger. A triggerless way to express the disjointedness (but not the union) is:

  • a type discriminator/tag column student_type (say) in GradStudent, UndergradStudent & Student with additional FOREIGN (super) KEYs (id,student_type) from GradStudent and UndergradStudent to NOT NULL UNIQUE (id,student_type) in Student
  • GradStudent CHECK( student_type = 'grad' ) and UndergradStudent CHECK ( student_type = 'undergrad' )

Rows in each of the two student subtype base tables are all the same (redundancy) and rows in Student are determined by their id (redundancy) but that's the cost in this case of having no triggers. Column student_type could be a computed column.

There's really no pretty SQL way to enforce that every parent id is a child. Having only the LEFT JOIN of the above child tables instead of the parent and child tables enforces that every parent is a child but requires NULL columns and further constraints. One needs triggers to reasonably constrain SQL databases. One uses idioms to get what declarative constraints one can.

For more on subtyping idioms see this answer and its links . Google 'stackoverflow database sql table' plus child/parent, super/subtables, super/subtypes, inheritance and/or polymorphism. Also multiple/many/two FKs/relationships/associations/references/links (although usually as in this question the constraint wanted is not a FK and the design should use subtypes instead). I googled "stackoverflow two foreign keys" and got this .

Just to recap: in a "is-a" relation, there are two main considerations.

The first one is whether the relation is partial or total . The second one is whether the relation is disjoint .

If it's partial, create separate tables for each entity type (in your case GradStudent , UndergradStudent and Student ). If it's total, create tables only for each subtype (in your case only GradStudent and UndergradStudent ).

If it's disjoint, create one general table with all possible fields, and additionally a type field. If it's not disjoint, create also one general table with all possible fields, plus fields for each possible type with a bool value.

As you can see, the solutions for the total and disjoint are contradictory. So, feel free to pick one of the implementations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM