Foreign key on a Foreign key - SQL Server - sql

I'm creating a database for a project in which I need to declare a foreign key on another foreign key for the sake of a checking constraint.
I have a Person table and a Groups table, both of these contain a DepartmentID. Whenever I insert a new task in the Task table, I want to check that the Groups.DepartmentID matches the Person.DepartmentID.
The idea is that a task is linked to a person and has 2 types, a grouptype which defines if its database work, financial work etc and a tasktype which defines if its maintenance, training etc. When a person tries to add a task with a groupType that is not for his/her department it should fail.
I tried adding these attributes to the Task table as a foreign key, however declaring a foreign key on a non-unique or non-primary key isn't accepted in Microsoft SQL Server (the DepartmentID in the Person and Group tables cannot be unique!).
Anyone knows how to fix this?
CREATE TABLE Department
(
ID int PRIMARY KEY IDENTITY,
Name varchar(50),
UNIQUE ("Name")
)
CREATE TABLE Groups
(
ID int IDENTITY,
GroupType varchar(50) PRIMARY KEY,
Description varchar(255) DEFAULT ('-'),
DepartmentID int
FOREIGN KEY (DepartmentID) REFERENCES Department(ID),
)
CREATE TABLE Person
(
ID int PRIMARY KEY IDENTITY,
Name varchar(50),
DepartmentID int
FOREIGN KEY (DepartmentID) REFERENCES Department(ID)
)
CREATE TABLE TaskType
(
ID int IDENTITY,
TaskType varchar(50) PRIMARY KEY,
Description varchar(255) DEFAULT ('-'),
)
CREATE TABLE Task
(
ID int IDENTITY,
TimeFrame decimal(4,2),
Yearcount int,
GroupType varchar(50),
TaskType varchar(50),
WeekNr int,
ExceptionDetail varchar(255) DEFAULT ('-'),
PersonID int
)
These are the FK attributes in the task table that are not accepted:
GDID int FOREIGN KEY REFERENCES Groups(DepartmentID),
PDID int FOREIGN KEY REFERENCES Person(DepartmentID),
CHECK (GDID = PDID),
UNIQUE ("TaskType", "GroupType", "WeekNr", "Yearcount"),
FOREIGN KEY (TaskType) REFERENCES TaskType(TaskType),
FOREIGN KEY (PersonID) REFERENCES Person(ID),
FOREIGN KEY (GroupType) REFERENCES Groups(GroupType)

Add wider "super keys" to these tables that include the primary key and additional columns1, then declare the foreign keys using them. Whether you also remove the superfluous smaller foreign keys is a matter of taste:
CREATE TABLE Groups(
ID int IDENTITY,
GroupType varchar(50) PRIMARY KEY,
Description varchar(255) DEFAULT ('-'),
DepartmentID int FOREIGN KEY (DepartmentID) REFERENCES Department(ID),
constraint Group_Dep_XRef UNIQUE (GroupType,DepartmentID)
)
CREATE TABLE Person(
ID int PRIMARY KEY IDENTITY,
Name varchar(50),
DepartmentID int FOREIGN KEY (DepartmentID) REFERENCES Department(ID),
constraint Person_Dept_XRef UNIQUE (ID,DepartmentID)
)
CREATE TABLE Task(
ID int IDENTITY,
TimeFrame decimal(4,2),
Yearcount int,
GroupType varchar(50),
TaskType varchar(50),
WeekNr int,
ExceptionDetail varchar(255) DEFAULT ('-'),
PersonID int,
DepartmentID int,
constraint FK_Group_Dept_XRef FOREIGN KEY (GroupType,DepartmentID)
references Group (GroupType,DepartmentID),
constraint FK_Person_Dept_XRef FOREIGN KEY (PersonID,DepartmentID)
references Person (ID,DepartmentID),
UNIQUE ("TaskType", "GroupType", "WeekNr", "Yearcount"),
FOREIGN KEY (TaskType) REFERENCES TaskType(TaskType),
FOREIGN KEY (PersonID) REFERENCES Person(ID), --Redundant now
FOREIGN KEY (GroupType) REFERENCES Groups(GroupType) --Also redundant
)
(I also consolidated GDID and PDID into DepartmentID - if they're always meant to be equal, why store that twice and then have to have another constraint to assert their equality?)
1If a primary key (or unique key) is sufficient to uniquely identify each row then any wider key which includes the key columns and additional columns must also be sufficient to uniquely identify each row.

Related

error while creating both of these tables or when foreign key contraints are added

Whenever I try to create these two tables in oracle live SQL it gives right parenthesis error.
CREATE TABLE Section_Table (
Status_ID INT Primary Key,
Names varchar(20),
course_id int FOREIGN KEY references Course_Table(course_id),
Schedule_id int FOREIGN KEY references Schedule_Table(Schedule_id),
Instruction_id int
);
CREATE TABLE Enrollment_Table (
ENROLLMENT_ID INT PRIMARY KEY,
STUDENT varchar(20),
course_id INT FOREIGN KEY REFERENCES Course_Table(course_id),
LEVEL_ID INT FOREIGN KEY REFERENCES Level_Table(LEVEL_ID),
Status_id INT FOREIGN KEY REFERENCES Status_Table(Status_ID),
DATE_ENROLLED DATE
);

ERROR :ORA-02264: name already used by an existing constraint

create table ward
(
wnum int primary key,
wname varchar(30),
phoneno int,
wloc varchar(50),
chnursename varchar(20) constraint ward_fk references charge_nurse
);
create table charge_nurse
(
chnurse varchar(20) constraint charge_nurse_pk primary key,
stnum int constraint charge_nurse_fk references staff
);
create table staff
(
stname varchar(20),
stnum int constraint staff_pk primary key,
addr varchar(20),
phoneno int,
stposition varchar(30),
specality varchar(30) unique,
shift varchar(10),
noofhoursperweek int
);
create table generalsupplies
(
itnum int constraint generalsupplies_pk primary key,
itname varchar(20) unique,
quantityinstock int,
reorder varchar(10),
despt varchar(10),
costperunit int
);
create table pharmasupplies
(
dnum int constraint pharmasupplies_pk primary key,
dname varchar(30) unique,
despt varchar(20),
dosage_Mg int,
quantityinstock int,
reorder varchar(10),
costperunit int
);
While creating the below table I am facing problem:
ORA-02264: name already used by an existing constraint
create table centralsupplies
(
wardnum int constraint centralsupplies_fk references ward,
itemnum int constraint centralsupplies_fk references generalsupplies,
drugnum int constraint centralsupplies_fk references pharmasupplies,
quantity_required varchar(20),
staffname varchar(10) references staff(stname),
staffnum int constraint centralsupplies_fk references staff,
regnum int unique,
dateord date,
daterec date
);
How do I solve this problem?
You use 3 times the same constraint name centralsupplies_fk in your centralsupplies table.
3 constraints = 3 constraint names
Your create table statement has four foreign keys all called centralsupplies_fk. That is not allowed: constraint names must be unique within a schema. You must give each one a different name.
It is usual practice to include the referenced table in the key name. So
create table centralsupplies
(
wardnum int constraint centralsupplies_ward_fk references ward,
itemnum int constraint centralsupplies_generalsupplies_fk references generalsupplies,
drugnum int constraint centralsupplies_pharmasupplies_fk references pharmasupplies,
quantity_required varchar(20),
staffname varchar(10) references staff(stname),
staffnum int constraint centralsupplies_staff_fk references staff,
regnum int unique,
dateord date,
daterec date
)
Also you have another foreign key constraint on STAFFNAME which you have not named. You do not need to name constraints, the system will generate a unique one for you, but it's generally a good idea to name them, not least because it is easier to diagnose relational integrity error messages with meaningfully named constraints.
However, in this case the correct solution is to drop the STAFFNAME column. You already have a foreign on the STAFF table, and you should join to that table whenever you need to display a value for STAFFNAME. Besides you do not have a unique constraint on staff.stname column, so the foreign key statement will fail: foreign keys can only reference primary or unique keys.

Problems when creating a table referencing other with FK

I'm trying to create a database for a project that works like a school with some teachers,courses,classes etc.
I need to create a new Table involving 2 tables however I'm getting an error when creating the table Classes_Teachers.
There are no primary or candidate keys in the referenced table 'Classes' that match the referencing column list in the foreign key 'FK__Classes_T__Class__11007AA7'.
Here is my SQL Code:
CREATE TABLE Teachers(
id INT,
name varchar(40),
email varchar(30) FOREIGN KEY REFERENCES Users(email),
PRIMARY KEY(id)
);
CREATE TABLE Courses(
name varchar(20),
acr varchar(4),
teacher int FOREIGN KEY REFERENCES Teachers(id),
PRIMARY KEY(acr)
);
CREATE TABLE Classes(
id varchar(2),
courses_acronym varchar(4) FOREIGN KEY REFERENCES Courses(acr),
year_Semesters varchar(5),
PRIMARY KEY(id,courses_acronym),
);
CREATE TABLE Classes_Teacher(
Classes_id varchar(2) FOREIGN KEY REFERENCES Classes(id),
Teachers_id INT FOREIGN KEY REFERENCES Teachers(id),
courses_acronym varchar(4) FOREIGN KEY REFERENCES Classes(courses_acronym),
PRIMARY KEY(Classes_id,courses_acronym)
);
The error comes from the foreign keys declared in table Classes_Teacher. To relate to the Classes table, you want to use both primary columns of the referred tables, instead of twn separated foreign keys.
Consider:
CREATE TABLE Classes_Teacher(
Classes_id varchar(2),
Teachers_id INT FOREIGN KEY REFERENCES Teachers(id),
courses_acronym varchar(4),
FOREIGN KEY (Classes_id, courses_acronym) REFERENCES Classes(id, courses_acronym),
PRIMARY KEY(Classes_id,courses_acronym)
);
Demo on DB Fiddle.
In table Classes you define a Primary Key on two columns. This is probably not needed if courses_acronym depends on ID.
CREATE TABLE Classes(
id varchar(2),
courses_acronym varchar(4) FOREIGN KEY REFERENCES Courses(acr),
year_Semesters varchar(5),
PRIMARY KEY(id),
);
In table Classes_Teacher you refer Classes twice. Shouldn't the second Foreign Key refer Courses?
CREATE TABLE Classes_Teacher(
Classes_id varchar(2) FOREIGN KEY REFERENCES Classes(id),
Teachers_id INT FOREIGN KEY REFERENCES Teachers(id),
courses_acronym varchar(4) FOREIGN KEY REFERENCES Courses(acr),
PRIMARY KEY(Classes_id,courses_acronym)
);

SQL: Foreign key references a composite primary key

I'm new to SQL and there are a lot of things going on that I still don't seem to quite understand. I have the following table
CREATE TABLE Person
(
First_Name varchar(20) NOT NULL,
Name varchar(20) NOT NULL,
Address varchar(50) NOT NULL,
PRIMARY KEY (First_Name, Name, Address)
);
I know want to create another table that has the primary key from the table Person as foreign key and also as primary key:
CREATE TABLE Purchase
(
No_Installments int,
Rate int,
Person varchar(50) NOT NULL PRIMARY KEY,
CONSTRAINT PFK
FOREIGN KEY (Person) REFERENCES Person (First_Name, Name, Address)
);
For some reason this doesn't work and I get an error every time. I've already looked up the other threads here on stackoverflow, but they don't really seem to help me. What am I doing wrong?
If you have a compound PK made up from three columns, then any child table that wants to establish a foreign key relationship must ALSO have all those 3 columns and use all 3 columns to establish the FK relationship.
FK-PK relationship is an all or nothing proposal - you cannot reference only parts of a primary key - either you reference all columns - or you don't reference.
CREATE TABLE Purchase
(
No_Installments int,
Rate int,
Person varchar(50) NOT NULL PRIMARY KEY,
First_Name varchar(20) NOT NULL,
Name varchar(20) NOT NULL,
Address varchar(50) NOT NULL,
CONSTRAINT PFK
FOREIGN KEY (First_Name, Name, Address)
REFERENCES Person (First_Name, Name, Address)
);
Have an integer primary key, using identity, auto_increment, serial or whatever for your database:
CREATE TABLE Person (
PersonId int identity PRIMARY KEY
First_Name varchar(20) NOT NULL,
Name varchar(20) NOT NULL,
Address varchar(50) NOT NULL,
CONSTRAINT unq_person_3 UNIQUE (First_Name, Name, Address)
);
Then use the identity column for the reference:
CREATE TABLE Purchase (
PurchaseId int identity PRIMARY KEY,
No_Installments int,
Rate int,
PersonId int,
CONSTRAINT PFK
FOREIGN KEY (PersonId) REFERENCES Person (PersonId)
);
Notes:
You really don't want to have to deal with a composite primary key. Have you thought about what the joins will look like?
You don't want a primary key where the values are subject to change. What happens when someone changes his/her name? When someone moves?
Person should not be the primary key in Purchases. Are you only allowing someone to make one purchase?
As noted initially, how you generate such a column varies by database; identity happens to be the way that SQL Server does this.
You probably want to assign a unique ID to each person, not relying on their name to be unique or for an address to be required. That ID will be your Primary key and foreign key. Your purchase table should also have its own id for its primary key -- otherwise because primary keys must be unique, each person can only have one purchase.
CREATE TABLE Person (
id serial NOT NULL,
First_Name varchar(20) NOT NULL,
Name varchar(20) NOT NULL,
Address varchar(50) NOT NULL,
PRIMARY KEY (id));
CREATE TABLE Purchase (
id serial NOT NULL,
No_Installments int,
Rate int,
Person int NOT NULL,
FOREIGN KEY (Person) REFERENCES Person (id),
PRIMARY KEY (id));

Error when setting foreign key in SQL Server

I have the following queries that I run to create tables in MS SQL Server:
CREATE TABLE menus
(
menu_id int NOT NULL PRIMARY KEY,
menu_name char,
other_details char
)
CREATE TABLE bookings
(
booking_Id int NOT NULL PRIMARY KEY,
date_booked DATE,
date_of_booking DATE,
other_details char,
staff_id int FOREIGN KEY REFERENCES staff(staff_id),
customer_id int FOREIGN KEY REFERENCES customers(customer_id)
)
CREATE TABLE menus_booked
(
menu_id INT NOT NULL,
booking_id INT NOT NULL,
CONSTRAINT PK_menus_booked PRIMARY KEY(menu_id,booking_id),
FOREIGN KEY (menu_id) REFERENCES menus(menu_id),
FOREIGN KEY (booking_id) REFERENCES bookings(booking_id)
)
CREATE TABLE menu_changes
(
change_id int NOT NULL PRIMARY KEY,
menu_id int NOT NULL,
booking_id int NOT NULL,
change_details char,
FOREIGN KEY (menu_id) REFERENCES menus_booked(menu_id),
FOREIGN KEY (booking_id) REFERENCES menus_booked(booking_id)
)
On running the last query I get the error:
There are no primary or candidate keys in the referenced table 'menus_booked' that match the referencing column list in the foreign key 'FK_menu_chan_menu'
I am unsure if my queries are correct and can't resolve this error.
The primary key of menus_booked is a unique combination of menu_id and booking_id. A foreign must point to that combination, not just one of its fields, which is not necessarily unique. Your query currently tries to define two foreign keys, one on each column, instead of one foreign key on the combination of the columns:
CREATE TABLE menu_changes
(
change_id int NOT NULL PRIMARY KEY,
menu_id int NOT NULL,
booking_id int NOT NULL,
change_details char,
FOREIGN KEY (menu_id, booking_id)
REFERENCES menus_booked(menu_id, booking_id) -- Here!
)
A foreign key has to reference a primary key (or unique key but here the PK is the problem), and it has to reference it in it's entirety.
FOREIGN KEY (menu_id) REFERENCES menus_booked(menu_id),
FOREIGN KEY (booking_id) REFERENCES menus_booked(booking_id)
You have two foreign key's referencing part of the primary key of menus_booked. You'll have to alter it to:
FOREIGN KEY (menu_id, booking_id) REFERENCES menus_booked(menu_id, booking_id)