SQL: Foreign key references a composite primary key - sql

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

Related

References with PostgreSQL

I have this table:
CREATE TABLE cars_info.cars
(
id SERIAL,
owner_id INTEGER,
brand VARCHAR(50) NOT NULL,
model VARCHAR(50) NOT NULL,
color VARCHAR(50) NOT NULL,
register_number VARCHAR(50) NOT NULL,
created DATE NOT NULL,
PRIMARY KEY(id, brand, model, color, register_number, created),
CONSTRAINT fk_owner_id
FOREIGN KEY(owner_id)
REFERENCES persons_info.persons(id)
);
But when I tried create another table like this:
CREATE TABLE cars_info.violations
(
id SERIAL PRIMARY KEY,
car_id INTEGER NOT NULL,
message VARCHAR(100) NOT NULL,
active BOOLEAN NOT NULL,
CONSTRAINT fk_car_id
FOREIGN KEY(car_id)
REFERENCES cars_info.cars(id)
);
I get an error about that
Target external table "cars" does not have a unique constraint corresponding to the given keys
How can I fix that? I'm a beginner in SQL and don't know how to go about googling that
Your primary key definition for cars
PRIMARY KEY(id, brand, model, color, register_number, created)
makes no sense: The id column, being serial, is itself unique and it alone should be the primary key.
Delete your primary key definition and change the id column definition to:
id serial not null primary key
Unrelated, but best practice is to name table in the singular; name your tables car and violation rather than cars and violations

How to insert a composite primary key into another table?

I have a composite primary key that I would like to insert into another table.
create table courses_instructors
(
courseID int foreign key references Course(C_ID) not null,
instructorID int foreign key references Instructor(I_ID) not null,
primary key (courseID, instructorID), --coourseID and instructorID combined is the composite PK
courseTerm varchar(50) not null,
courseNumber int not null,
courseLocation varchar(50),
courseTime varchar(50),
courseMaxOccupancy int,
courseSeatAvailable int
)
create table courses_students
(
studentID int foreign key references student(S_ID) not null,
courseID int, -- foreign key -- I want this value to the be value that represents the composite PK from the courses_instructors
primary key(studentID, courseID), -- these 2 fields combined would make the composite PK, but with the courseID value I will be able to identify who is the instructor for a course and the other details from the course_instructor table
courseOutcome varchar(50)
)
All the course come from a course table which only contains the course name and the disciple along with a descrption. The course table has a primary key that identifies each course uniquely.
To refer composit primary key, Courses_Students table should be having both the columns CourseID and InstructorID.
And then
ALTER TABLE Courses_Students
ADD CONSTRAINT FK_Courses_Students
FOREIGN KEY(CourseID, InstructorID) REFERENCES Courses_Instructors(CourseID, InstructorID)
Or the table definitions should look like,
create table courses_instructors
(
courseID int foreign key references Course(C_ID) not null,
instructorID int foreign key references Instructor(I_ID) not null,
primary key (courseID, instructorID), --coourseID and instructorID combined is the composite PK
courseTerm varchar(50) not null,
courseNumber int not null,
courseLocation varchar(50),
courseTime varchar(50),
courseMaxOccupancy int,
courseSeatAvailable int
)
create table courses_students
(
studentID int foreign key references student(S_ID) not null,
courseID int,
instructorId int,
FOREIGN KEY(CourseID, InstructorID) REFERENCES Courses_Instructors(CourseID, InstructorID),
primary key(studentID, courseID, InstructorId),
courseOutcome varchar(50)
)
You can either refer two columns as already mentioned or add a surrogate key such as an identity column or GUID to the primary table and refer with to it - It usually performs better.
The course_instructors table is an intersection table implementing an m-m relationship between, as may be easily guessed, course entities and instructor entities. Almost invariably, I don't add a surrogate key to such a table for the simple reason that such a key would never be used. A typical user has a reference to one entity or the other and wishes to see all the other entities it relates to. Or sometimes the user has references to both entities and wished to get the details of their relationship.
This rule is not without exceptions, however, and your use case is just such an example. The table not just expresses a relationship between two entities but becomes an entity unto itself: a class offering. A student will select a class from a published schedule for the class and day/time desired. This will be identified by a class code number of some sort.
This code is what will be used to register for the desired class. In cases such as these, it makes sense to create a surrogate key for the intersection table -- which then becomes the class code printed in the catalog. Thus you would use this class code to refer to the relationship that defines the class offering and not use the composite key.
It looks like you already have such a composite key: the course_number field. You don't have it defined as unique but doesn't it uniquely identity the combination of course, instructor, location and time that makes up each class offering?

There are no primary or candidate keys in the referenced table error

I have a problem with combining foreign keys to different tables. For example I made a table Customers and a Table invoices. I want a foreign key from Customers to invoices so I can get the name and everything of the Customer:
Create table code of Customers:
Create Table Customers
(
customerID int IDENTITY(100,1) NOT NULL,
customer_email varchar(30) NOT NULL,
username varchar(255) NOT NULL,
password varchar(50) NOT NULL,
firstname varchar(255) NOT NULL,
lastname varchar(255) NOT NULL,
insertion varchar(10) NULL,
phonenumber int NULL,
streetname varchar(20) NOT NULL,
number int NOT NULL,
zipcode varchar(10) NOT NULL,
city varchar(255) NOT NULL,
Constraint pk_Customers
PRIMARY KEY (customerID, customer_email, username)
)
Create table code of Invoices:
Create Table Invoices
(
invoiceID int IDENTITY(1000,1) NOT NULL,
customer_email varchar(30) NOT NULL,
customerID int NOT NULL,
creationdate datetime NOT NULL DEFAULT GETDATE(),
totalAmount decimal(5,2) NOT NULL,
Constraint pk_Invoices
PRIMARY KEY (invoiceID, customer_email,creationdate)
)
The foreign key code that I want to use:
ALTER Table Invoices
ADD Constraint fk_Customers_Invoices
FOREIGN KEY (customerID) REFERENCES Customers (customerID)
ON UPDATE CASCADE
ON DELETE NO ACTION
It throws the following error:
There are no primary or candidate keys in the referenced table 'Customers' that match the referencing column list in the foreign key 'fk_Customers_Invoices'.
How can I add my foreign key?
I think it's because your primary key is a composite key:
customerID, customer_email, username
This suggests that it is only the combination of these three fields that will uniquely identify a customer, and the foreign key would need to reference all three fields.
If customerID is unique, then it should be the primary key for the table and your foreign keys would be able to use it as a reference.
For what purpose are the other fields included in the primary key?
Since your Customers table defines this primary key:
Constraint pk_Customers
PRIMARY KEY (customerID, customer_email, username)
any table that wants to reference Customers must provide all three columns of that primary key. That's the way FK constraints work.
So from your Invoices tables, you must provide all 3 columns that make up the primary key of Customers - not just one. You can never refernce only part of a primary key - it's the whole key or nothing....
ALTER Table Invoices
ADD Constraint fk_Customers_Invoices
FOREIGN KEY (customerID) REFERENCES Customers (customerID)
ON UPDATE CASCADE
ON DELETE NO ACTION
You can either:
change the PK for Customers to be just CustomerID which would make a whole lot more sense since it's an identity column
or you could add the other two columns in the Customers PK to yoru table Invoices

SQL Constraints Confusion

I'm in a bit of a mix right now, I have a Table called Avatars, which has a foreign key called Family. Now, in the family table, I have two Foreign Keys called Mother and Father - Now this is the confusing bit, in both the Mother and Father Tables, there is a Foreign key called Avatar_ID which is of course the Primary Key to the Avatars table. I'm not sure if that's even allowed in SQL PLUS.
Whenever I try and enter the tables 'Family, Mother or Father', I keep getting the error:ORA-02291: integrity constraint (SG304.FK_FATHER_ID) violated - parent key not found.
Is there any way around this? Or will I have to change my code completely? A sample of the code is below.
CREATE TABLE Avatars (
Avatar_ID VARCHAR(10) NOT NULL,
Avatar_Name VARCHAR(30),
AvA_DOB DATE,
Age VARCHAR(30),
Gender VARCHAR(30),
Strength_Indicated INT,
Hoard INT,
Avatar_Level VARCHAR(30),
Skill VARCHAR(30),
Original_Owner VARCHAR(30),
Family_ID VARCHAR(10) NOT NULL,
Species_ID VARCHAR(10) NOT NULL,
Inventory_ID VARCHAR(30) NOT NULL,
Weapon_ID VARCHAR(10),
Player_ID VARCHAR(10) NOT NULL,
PRIMARY KEY (Avatar_ID));
CREATE TABLE Family (
Family_ID VARCHAR(10) NOT NULL,
Mother_ID VARCHAR(10) NOT NULL,
Father_ID VARCHAR(10) NOT NULL,
primary key(Family_ID)
);
CREATE TABLE Mother (
Mother_ID VARCHAR(10) NOT NULL,
Avatar_ID VARCHAR(10) NOT NULL,
primary key(Mother_ID)
);
CREATE TABLE Father (
Father_ID VARCHAR(10) NOT NULL,
Avatar_ID VARCHAR(10) NOT NULL,
primary key(Father_ID)
);
ALTER TABLE Avatars
ADD CONSTRAINT fk_Family_ID
FOREIGN KEY (Family_ID)
REFERENCES Family(Family_ID);
ALTER TABLE Family
ADD CONSTRAINT fk_Mother_ID
FOREIGN KEY (Mother_ID)
REFERENCES Mother(Mother_ID);
ALTER TABLE Family
ADD CONSTRAINT fk_Father_ID
FOREIGN KEY (Father_ID)
REFERENCES Father(Father_ID);
ALTER TABLE Father
ADD CONSTRAINT fk_Avatar_ID
FOREIGN KEY (Avatar_ID)
REFERENCES Avatars(Avatar_ID);
ALTER TABLE Mother
ADD CONSTRAINT fk_Avatars_ID
FOREIGN KEY (Avatar_ID)
REFERENCES Avatars(Avatar_ID);
INSERT INTO Avatars (Avatar_ID,Avatar_Name,AvA_DOB,Age,Gender,Strength_Indicated,Hoard,Avatar_Level, Skill, Original_Owner, Family_ID,Species_ID,Inventory_ID,Player_ID) VALUES
('Ava01','Verda','20-JAN-2014','1 year 2 months','Female','100','20','Master','Leader',' - ',' - ','DRA1','MasterInventory','Player07');
Thanks in advance for any help given! (:
Foreign key refers to a record in parent table. In your INSERT statement you are inserting value ' - ' into a column parent_id. In this error message oracle informs you that there is no record with value ' - ' in a column family_id of a table family. As I can understand, you are trying to use ' - ' as 'absence of value'. There is special value for that - NULL. So you need to write your statement as:
INSERT INTO Avatars (Avatar_ID, Avatar_Name, AvA_DOB,
Age, Gender, Strength_Indicated, Hoard, Avatar_Level, Skill,
Original_Owner, Family_ID, Species_ID, Inventory_ID, Player_ID)
VALUES ('Ava01', 'Verda', '20-JAN-2014', '1 year 2 months' ,'Female',
'100', '20', 'Master', 'Leader', NULL, NULL, 'DRA1',
'MasterInventory', 'Player07');
Also I can recommend some changes to your schema. First of all, use number data type for primary keys - it allows you to use sequences to generate unique values. Also, I don't know details of the problem, but "family relations" in your tables look a bit complicated. You can describe it in a single table:
create table family_tree (
person_id number primary key,
father_id number,
mother_id number,
sex char(1),
name varchar2(50),
family_name varchar2(50));
add constraint fk_mother_id foreign key (mother_id)
references family_tree (person_id);
add constraint fk_father_id foreign key (father_id)
references family_tree (person_id);

Created Primary Key on SQL Server not Identified

CREATE TABLE sampProduct
(
Product_ID VARCHAR(15) NOT NULL,
Supplier_ID INT NOT NULL,
Category_ID INT NOT NULL,
Unit_Price DECIMAL(10, 2)
PRIMARY KEY(Product_ID)
)
CREATE TABLE sampMachine
(
M_Product_ID VARCHAR(15) NOT NULL,
Serial_No VARCHAR(15) NOT NULL,
Machine_Model VARCHAR(20),
PRIMARY KEY(M_Product_ID, Serial_No),
FOREIGN KEY(M_Product_ID) REFERENCES sampProduct(Product_ID)
)
CREATE TABLE sampService
(
Service_ID VARCHAR(15) NOT NULL,
Serial_No VARCHAR(15) NOT NULL,
Complaint VARCHAR(40) NOT NULL,
PRIMARY KEY(Service_ID),
FOREIGN KEY(Serial_No) REFERENCES sampMachine(Serial_No)
)
Machine is a subtype of Product. M_ProductID is referencing the primary key of the parent table Product by this key. And Serial_No is used to uniquely identify a Machine. The problem is, I want to create a foreign key from Serial_No into the Service table, since I want to track the serial numbers of the machine (this is because, for example, we can have many machine for each model or type, but each of them has their unique serial numbers), but there is an error for the creation. Can you help me out?
One of the requirements for creating a foreign key is that the table you reference must have a unique key on the columns you want referenced. So in your example in order for it to work you would need a unique key on sampMachine (Serial_No) so that you could create foreign keys to it using just Serial_No. The way you have it now you would need to use M_Product_Id in the table sampService and add it to the foreign key definition.
create table sampService(
M_Product_ID varchar(15) not null,
Service_ID varchar(15) not null,
Serial_No varchar(15) not null,
Complaint varchar(40) not null,
primary key (Service_ID),
foreign key (Serial_No) references sampMachine(m_Product_Id, Serial_No)
)