SQL: can many to many relationship have a PK in addition to the FKs from the other entities - sql

I'm having problem in inserting the values of an exam in the DB, and the reason is that every question that have been taking in the exam need to be unique which is not the case, we want the system to allow us to duplicate questions in the 60 question exam. what can I do to make this happened?
Exam (ExamID, Student.UID, ExamFB, Evaluated, ExamLevel)
Primary key (ExamID)
Foreign Key (Student.UID)
Contains (ExamID, QID, X, Y, StdAnswer, CorrectAnswer, QuestionFB)
Primary key (ExamID, QID)
Question (QID, SecID, Supervisor.UID, QBody, LawID)
Primary key (QID)
Foreign key (SecID, Supervisor.UID)

Yes, a many to many junction table does not have to be unique, although in your scenario I imagine it should be, I don't see why you would have the same question more than once on an exam, however it is quite a common scenario, to pick a slightly different scenario, imagine a service history of a car, you might have a table of mechanics, and a table of cars, and a table to store each service:
Mechanics - MechanicID (PK) Name
Cars - CarID (PK), RegistrationNumber, Make, Model
It is possible that the same mechanic will service the same car more than once, so you can't make the primary key (CarID, MechanicID), so you would either need to just assign a surrogate primary key to the service table:
Services - ServiceID (PK), CarID (FK), MechanicID(FK), ServiceDate
Or add an additional column to your table that will make the composite key unique, e.g in the above make the key (CarID, MechanicID, ServiceDate).
In your case you could have an additional column QuestionNumber (1 - 60 in your case) that identifies where the question appears in your exam, then your PK would just be (ExamID, QuestionNumber), and keep the foreign key to QuestionID.
So your database diagram would look something like one of the below:

Add an IDENTITY Attribute with the FKs together will be your PK

Related

When will it be considered an OVERKILL when making a composite primary key?

Recently, I stumbled upon this question when looking through my database notes.
In the case of an annual examination (A Levels, O Levels) where students who did not attain their desired marks are allowed for a re-sit in the following years,
suppose there was a database designed for the school to track that has the following attributes
Student ID, Exam module, Exam Date, Exam Results
Question provided by the book (not my personal question): what would be some appropriate primary keys?[5]
Now, I know that several primary key should not be used:
Purely Student ID
(Student ID + Exam Module)
And I also know that perhaps
Artificial Primary Key - extending a 5th column that auto-increments
(Student ID + Exam Module + Exam Date)
could be used as a primary key
My question comes from making a composite primary key from all attributes (Student ID + Exam Module + Exam Date + Exam Results). A part of me thinks it will work as a composite primary key but it does not make sense to provide every single table with a composite primary key consisting of all columns.
From your description of the question, the following tuple of columns should be unique throughout the table: (StudentID, ExamModule, ExamDate), because a student may take the same exam on different dates (actually: different years). The result of the exam should not be part of this unique column tuple: this prevents a student to two results for the same exam.
Whether you decide to make this tuple of columns the primary key of your table or use some kind of serial column as primary key is mostly a matter of taste. If you go for a serial key, you need to put a composite unique constraint on the three above columns anyway.
This is not necessarily along the line of the OP's initial question:
Question: what would be some appropriate primary keys?
but..(in hind site) I would have an IDENTITY field as a primary key.
And have the StudentID as just an Index (non unique) and as an alternate Key.

Is unique foreign keys across multiple tables via normalization and without null columns possible?

This is a relational database design question, not specific to any RDBMS. A simplified case:
I have two tables Cars and Trucks. They have both have a column, say RegistrationNumber, that must be unique across the two tables.
This could probably be enforced with some insert/update triggers, but I'm looking for a more "clean" solution if possible.
One way to achieve this could be to add a third table, Vehicles, that holds the RegistrationNumber column, then add two additional columns to Vehicles, CarID and TruckID. But then for each row in Vehicles, one of the columns CarID or TruckID would always be NULL, because a RegistrationNumber applies to either a Car or a Truck leaving the other column with a NULL value.
Is there anyway to enforce a unique RegistrationNumber value across multiple tables, without introducing NULL columns or relying on triggers?
This is a bit complicated. Having the third table, Vehicles is definitely part of the solution. The second part is guaranteeing that a vehicle is either a car or a truck, but not both.
One method is the "list-all-the-possibilities" method. This is what you propose with two columns. In addition, this should have a constraint to verify that only one of the ids is filled in. A similar approach is to have the CarId and TruckId actually be the VehicleId. This reduces the number of different ids floating around.
Another approach uses composite keys. The idea is:
create table Vehicles (
Vehicle int primary key,
Registration varchar(255),
Type varchar(255),
constraint chk_type check (type in ('car', 'truck')),
constraint unq_type_Vehicle unique (type, vehicle), -- this is redundant, but necessary
. . .
);
create table car (
VehicleId int,
Type varchar(255), -- always 'car' in this table
constraint fk_car_vehicle foreign key (VehicleId) references Vehicles(VehicleId),
constraint fk_car_vehicle_type foreign key (Type, VehicleId) references Vehicles(Type, VehicleId)
);
See the following tags: class-table-inheritance shared-primary-key
You have already outlined class table inheritance in your question. The tag will just add a few details, and show you some other questions whose answers may help.
Shared primary key is a handy way of enforcing the one-to-one nature of IS-A relationships such as the relationship between a vehicle and a truck. It also allows a foreign key in some other table to reference a vehicle and also a truck or a car, as the case may be.
You can add the third table Vehicles containing a single column RegistratioNumber on which you apply the unique constraint, then on the existing tables - Cars and Trucks - use the RegistrationNumber as a foreign key on the Vehicles table. In this way you don't need an extra id, avoid the null problem and enforce the uniqueness of the registration number.
Update - this solution doesn't prevent a car and a truck to share the same registration number. To enforce this constraint you need to add either triggers or logic beyond plain SQL. Otherwise you may want to take a look at Gordon's solution that involves Composite Foreign Keys.

MS SQL creating many-to-many relation with a junction table

I'm using Microsoft SQL Server Management Studio and while creating a junction table should I create an ID column for the junction table, if so should I also make it the primary key and identity column? Or just keep 2 columns for the tables I'm joining in the many-to-many relation?
For example if this would be the many-to many tables:
MOVIE
Movie_ID
Name
etc...
CATEGORY
Category_ID
Name
etc...
Should I make the junction table:
MOVIE_CATEGORY_JUNCTION
Movie_ID
Category_ID
Movie_Category_Junction_ID
[and make the Movie_Category_Junction_ID my Primary Key and use it as the Identity Column] ?
Or:
MOVIE_CATEGORY_JUNCTION
Movie_ID
Category_ID
[and just leave it at that with no primary key or identity table] ?
I would use the second junction table:
MOVIE_CATEGORY_JUNCTION
Movie_ID
Category_ID
The primary key would be the combination of both columns. You would also have a foreign key from each column to the Movie and Category table.
The junction table would look similar to this:
create table movie_category_junction
(
movie_id int,
category_id int,
CONSTRAINT movie_cat_pk PRIMARY KEY (movie_id, category_id),
CONSTRAINT FK_movie
FOREIGN KEY (movie_id) REFERENCES movie (movie_id),
CONSTRAINT FK_category
FOREIGN KEY (category_id) REFERENCES category (category_id)
);
See SQL Fiddle with Demo.
Using these two fields as the PRIMARY KEY will prevent duplicate movie/category combinations from being added to the table.
There are different schools of thought on this. One school prefers including a primary key and naming the linking table something more significant than just the two tables it is linking. The reasoning is that although the table may start out seeming like just a linking table, it may become its own table with significant data.
An example is a many-to-many between magazines and subscribers. Really that link is a subscription with its own attributes, like expiration date, payment status, etc.
However, I think sometimes a linking table is just a linking table. The many to many relationship with categories is a good example of this.
So in this case, a separate one field primary key is not necessary. You could have a auto-assign key, which wouldn't hurt anything, and would make deleting specific records easier. It might be good as a general practice, so if the table later develops into a significant table with its own significant data (as subscriptions) it will already have an auto-assign primary key.
You can put a unique index on the two fields to avoid duplicates. This will even prevent duplicates if you have a separate auto-assign key. You could use both fields as your primary key (which is also a unique index).
So, the one school of thought can stick with integer auto-assign primary keys, and avoids compound primary keys. This is not the only way to do it, and maybe not the best, but it won't lead you wrong, into a problem where you really regret it.
But, for something like what you are doing, you will probably be fine with just the two fields. I'd still recommend either making the two fields a compound primary key, or at least putting a unique index on the two fields.
I would go with the 2nd junction table. But make those two fields as Primary key. That will restrict duplicate entries.

Database design for patients and diseases [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I am creating an application (desktop) to store and retrieve patients' records along with diseases. As patients and diseases have a many to many relationship, so I've created three tables; PATIENTS, DISEASES and one is Junction table. As one patient can register more than once in a single disease over the time so 'PATIENTS' table contains composite primary key of patient's 'reference no' and 'registration date'. Table 'DISEASES' only contains 'name' as a primary key.
Now I am a little confused about the design of junction table. It is containing the composite primary key of 'PATIENTS' table and a primary key of 'DISEASES' table as foreign keys.
Should I make composite primary key of all these foreign keys in junction table or create another primary key or something different?
Any help would be greatly appreciated.
It doesn't seem like that design is quite right. If the patient's reference number uniquely identifies the patient, then that should be the primary key. If the same patient can register for a given disease multiple times, then that should be part of the key in the junction table, not in the patient table.
The primary key in the junction table should be what uniquely identifies an association, which in this case should be a composite key composed of the key from the patient table, the disease table, and the registration date.
I would suggest you one more table for cases. This table would contain an entry date. You should not use the disease name as primary key. This would make it difficult to correct typos or simply to choose a more appropriate name in the future, or maybe you would want to have a Latin as well as an English name.
Patient table
-------------
PK PatientID
Name
DateOfBirth
etc.
Disease table
-------------
PK DiseaseID
Name
Case table
-------------
PK CaseID
FK PatientID
EntryDate
etc.
CaseDisease table
-------------
PK, FK CaseID
PK, FK DiseaseID
Now you have these relations
Patient --1:n--> Case --1:n--> CaseDisease <--n:1-- Disease
EDIT:
The case table might not be necessary for now and might seem to be over-designed. However, should it turn out in future, that you have to store other data to a case as well; the db design would not have to be changed fundamentally.
UPDATE:
Alternatively, you could do it without a case table. In that case, the junction table would have a date as part of the primary key
PatientDisease table
-------------
PK, FK PatientID
PK, FK DiseaseID
PK Date
The relations would be
Patient --1:n--> PatientDisease <--n:1-- Disease
'name' as a primary key is not a good idea - there shoud be an Id column in that table which should be set as primary key
DiseasesToPatients table should be made of both foreign keys - from Patients and Diseases tables and they should be set as composite primary key on that table.

implementing UNIQUE across linked tables in MySQL

a USER is a PERSON and a PERSON has a COMPANY - user -> person is one-to-one, person -> company is many-to-one.
person_id is FK in USER table.
company_id is FK in PERSON table.
A PERSON may not be a USER, but a USER is always a PERSON.
If company_id was in user table, I could create a unique key based on username and company_id, but it isn't, and would be a duplication of data if it was.
Currently, I'm implementing the unique username/company ID rule in the RoseDB manager wrapper code, but it feels wrong. I'd like to define the unique rule at the DB level if I can, but I'm not sure excactly how to approach it. I tried something like this:
alter table user add unique(used_id,person.company_id);
but that doesn't work.
By reading through the documentation, I can't find an example that does anything even remotely similar. Am I trying to add functionality that doesn't exist, or am I missing something here?
Well, there's nothing simple that does what you want. You can probably enforce the constraint you need using BEFORE INSERT and BEFORE UPDATE triggers, though. See this SO question about raising MySQL errors for how to handle making the triggers fail.
Are there more attributes to your PERSON table? Reason I ask is that what you want to implement is a typical corollary table:
USERS table:
user_id (pk)
USER_COMPANY_XREF (nee PERSON) table:
user_id (pk, fk)
company_id (pk, fk)
EFFECTIVE_DATE (not null)
EXPIRY_DATE (not null)
COMPANIES table:
company_id (pk)
The primary key of the USER_COMPANY_XREF table being a composite key of USERS.user_id and COMPANIES.company_id would allow you to associate a user with more than one company while not duplicating data in the USERS table, and provide referencial integrity.
You could define the UNIQUE constraint in the Person table:
CREATE TABLE Company (
company_id SERIAL PRIMARY KEY
) ENGINE=InnoDB;
CREATE TABLE Person (
person_id SERIAL PRIMARY KEY,
company_id BIGINT UNSIGNED,
UNIQUE KEY (person_id, company_id),
FOREIGN KEY (company_id) REFERENCES Company (company_id)
) ENGINE=InnoDB;
CREATE TABLE User (
person_id BIGINT UNSIGNED PRIMARY KEY,
FOREIGN KEY (person_id) REFERENCES Person (person_id)
) ENGINE=InnoDB;
But actually you don't need the unique constraint even in the Person table, because person_id is already unique on its own. There's no way a given person_id could reference two companies.
So I'm not sure what problem you're trying to solve.
Re your comment:
That doesn't solve the issue of allowing the same username to exist in different companies.
So you want a given username to be unique within one company, but usable in different companies? That was not clear to me from your original question.
So if you don't have many other attributes specific to users, I'd combine User with Person and add an "is_user" column. Or just rely on it being implicitly true that a Person with a non-null cryptpass is by definition a User.
Then your problem with cross-table UNIQUE constraints goes away.