问题
i'm building a DB of a graduation projects management system. Students are divided into groups .There is groups table and faculty table. Each group has an advisor and two examiners. i'm confused here. Should i create 3 FKs from the the faculty table? 2 for examiners and 1 for advisor?
here is the SQL code:
create table groups
(
groupID NUMBER not null,
nbStudents NUMBER not null,
avgGPA DOUBLE NOT NULL,
projectName varchar(50) not null,
advisorID NUMBER
examiner1ID NUMBER
examiner2ID NUMBER
primary key (groupID)
);
create table faculty
(
name varchar(30) not null,
facultyID NUMBER(10) not null,
email varchar(30) not null,
mobile NUMBER(15) not null,
type varchar
primary key (facultyID)
);
alter table groups
add constraint FK_EX1 foreign key (examiner1ID)
references faculty (facultyID) ;
alter table groups
add constraint FK_EX1 foreign key (examiner2ID)
references faculty (facultyID) ;
alter table groups
add constraint FK_EX1 foreign key (advisorID)
references faculty (facultyID) ;
回答1:
EDIT PENDING... see my first comment.
Just state the foreign keys as you find them.
A foreign key says that a value in a column in a table must appear as a value of a column in another (possibly the same) table where corresponding columns form a key. So in the given design just declare the FKs as you find them.
Although these aren't really FKs. First, in SQL a FK declaration actually declares a foreign superkey. Second, because those columns can be NULL. SQL says how it's going to check them, and it doesn't check when columns are NULL, and that's what you want. But that constraint just isn't a foreign (super)key. We just call it that in an SQL database.
Find statements that describe your application situtations then normalize.
It not non-normalized to have multiple columns per se. That is a common misconception.
However its generally contraindicated for at least an ideal design. Just find a parameterized statement parameterized by column names for every thing you need to say about a situation. Each statement gets a table.
// group [groupID] contains [nbStudents] students .... and has advisor [advisorID] and ...
groups(groupID,nbStudents,...,advisorID,examinerID)
The rows that make the statement true go in the table. Find all the statements you need to describe your application situations. Fill the tables with the rows that make their statements true.
Find simple statements and rearrange for NULL later.
Notice that the above statement is only true for rows with no NULLs. But you want to say sometimes that no faculty are in those roles.
Ideally you just want
// group [groupID] contains [nbStudents] students ... [projectName])
groups(groupID,nbStudents,...,projectName)
// [facultyID] advises [groupID]
advises(facultyID,groupID)
// [facultyID] examines [groupID]
examines(faculty,groupID)
With constraints about numbers of faculty per group. If you properly write a relational design without nulls then normalize you will get this sort of simple thing. Don't worry about the number of statements/tables. They just reflect the complexity of the application.
But SQL DBMSs generally don't suport constraints easily. So for certain reasons to do with SQL or performance we might to rearrange. But design null-free first. Ie pick straightforward statements & then normalize. Then rearrange soundly. (SOme rearranging might de-normalize, but not this particular case.)
Nulls complicate.
One problem with nulls is they complicate table meanings. Your design with nulls has table group
holding the rows that make this statement true:
//*
group [groupID] contains [nbStudents] students ....
AND ( [advisorID IS NULL they have no advisor
OR [advisorID] IS NOT NULL AND advisor [facultyID] advises them)
AND ( [examiner1ID IS NULL AND [examiner2ID] IS NULL and they have no examiner
OR [examiner1ID] IS NOT NULL AND [examiner2ID] IS NULL AND [examiner1ID] examines them
OR [examiner1ID] IS NULL AND [examiner2ID] IS NOT NULL AND [examiner2ID] examines them
OR [examiner1ID] IS NOT NULL AND [examiner2ID] IS NOT NULL
AND [examiner1ID] examines them AND [examiner2ID] examines them)
*//
groups(groupID,nbStudents,...,advisorID,examinerID)
Unless you cut out nulls back to the simple tables above when querying, your query meanings are complicated like this too. Ie queries give rows that make statements like that true.
On top of that when nulls are left in SQL gives you complex answers that do not mean "... and faculty unknown".
People have intuitive understanding of such nulls in base tables. But design first simply and soundly. Rearrange later. Be sure you properly cut out null-free parts and leave in null-free parts when you query.
来源:https://stackoverflow.com/questions/24243417/multiple-foreign-keys-from-the-same-table