Cannot add foreign key constraint, composite PK and FK - sql

CREATE TABLE HOSPITAL (
HOSP_CODE INT(3) NOT NULL,
HOSP_NAME VARCHAR(15),
HOSP_ADDRESS VARCHAR(15),
HOSP_PHONE VARCHAR(8),
HOSP_SUMBED INT(5),
PRIMARY KEY (HOSP_CODE)
);
CREATE TABLE WARD (
HOSP_CODE INT(3) NOT NULL,
WARD_CODE INT(3) NOT NULL,
WARD_NAME VARCHAR(20),
WARD_SUMBED INT(3),
PRIMARY KEY (HOSP_CODE, WARD_CODE),
FOREIGN KEY (HOSP_CODE) REFERENCES HOSPITAL(HOSP_CODE),
FOREIGN KEY (WARD_CODE) REFERENCES WARD(WARD_CODE)
);
I am trying to apply a constrain of a Primary Key that has 2 columns in it (HOSP_CODE and WARD_CODE) in table WARD and a Foreign Key constraint that is consisted of the two PK stated above.
Writing this code gives me the error stated in the title.
I have searched quite a lot about this error but couldn't find anything.
I understand that if there is a composite PK then the FK that refers to the same keys needs to be composite.
What I don't understand (and probably is the reason I have the error) is how can I assign the FK that refers to WARD_CODE.
Thank you in advance for your help and excuse me if I am unclear with my question.
P.S. I am new to SQL.
P.S2. The reason I need it this way is because of an assignment that a teacher gave us whose description mentions that table WARD should have a composite PK(HOSP_CODE,WARD_CODE) and two FKs for HOSP_CODE and WARD_CODE.

This is a bit long for a comment.
I think you might want three tables: Hospitals, Wards, and HospitalWards.
What you are calling Ward would be HospitalWards. You need a second table with one row per WardCode. I might think that the tables would look something like this:
CREATE TABLE WARDS (
WARD_CODE INT(3) NOT NULL,
WARD_NAME VARCHAR(20),
);
CREATE TABLE HospitalWards (
HOSP_CODE INT(3) NOT NULL,
WARD_CODE INT(3) NOT NULL,
WARD_NUMBED INT(3),
PRIMARY KEY (HOSP_CODE, WARD_CODE),
FOREIGN KEY (HOSP_CODE) REFERENCES HOSPITALS(HOSP_CODE),
FOREIGN KEY (WARD_CODE) REFERENCES WARDS(WARD_CODE)
);
The number of beds would be in the junction table. Many hospitals might have maternity wards, for instance, but each would have a different number of beds.
Note that I tend to name tables in the plural rather than the singular.

Related

Why is my create table failing? - does not match primary key

This is what I am trying to create:
CREATE TABLE VEHICLEREPORT
(
DeptID char(2) not null,
Vin# char(3) not null,
Miles varchar(6) not null,
Bill# char(3) not null,
EID char(3) not null,
PRIMARY KEY (DeptID, Vin#),
FOREIGN KEY (bill#) REFERENCES billing,
FOREIGN KEY (EID) REFERENCES Employee
);
The issue is with my reference to billing. The error says:
The number of columns in the referencing column list for foreign key 'FK__VEHICLERE__Bill#__5AEE82B9' does not match those of the primary key in the referenced table 'Billing'.
but my billing table entered fine:
CREATE TABLE BILLING
(
VIN# char(3),
BILL# char(3),
PRIMARY KEY (VIN#, Bill#),
FOREIGN KEY (VIN#) REFERENCES vehicle
);
What am i missing with this?
Appreciate the help.
If you think of the foreign key as establishing a parent-child relationship between two tables, then the parent side column(s) need to be unique.
From Wikipedia:
In the context of relational databases, a foreign key is a field (or collection of fields) in one table that uniquely identifies a row of another table or the same table. ... In simpler words, the foreign key is defined in a second table, but it refers to the primary key or a unique key in the first table.
In your example, there is no guarantee that VIN# is unique in VEHICLEREPORT. Below are your options
VIN# is guaranteed to be unique in VEHICLEREPORT. In this case add a UNIQUE constraint on VIN# on the VEHICLEREPORT table. The error will go away.
VIN# is not unique in VEHICLEREPORT (doesn't seem likely). If this is the case, then likely there is a flaw in the design of your BILLING table as it could likely point to more than one row in VEHICLEREPORT. You should consider adding DeptID column to BILLING and creating a composite foreign key.
Also if VIN# is unique (case 1 above), you should think of why DeptID is present in the PK. Maybe the right fix at the end is to drop DeptID from the primary key.

Are these FKs necessary -- and are they stopping me?

I'm having some difficulties with a database I'm creating for a summer camp, specifically with the PK and FK constraints. When I declare the FK constraint (e.g. FOREIGN KEY(PID) references Campers(CamperID)) I get an error running my code through pgAdmin (I'm using PostgreSQL). I understand that, for example, the Campers table is not yet created, and this is most likely part/all of the roadblock, however I feel like my FKs are still wrong somehow. To my understanding, a FK is a PK in another table -- but I feel like there is some redundancy or disconnect between my tables.
I've put the syntax for some of my CREATE statements below. I'm not sure if I'll get reprimanded for the quality of my (somewhat vague) question, but I feel a bit lost and would appreciate any help or advice. Thank you in advance!
DROP TABLE IF EXISTS People;
CREATE TABLE People (
PID VARCHAR(10) NOT NULL UNIQUE,
FName TEXT NOT NULL,
LName TEXT NOT NULL,
DOB DATE NOT NULL,
ArrivalDate DATE NOT NULL DEFAULT CURRENT_DATE,
DepartureDate DATE,
US_PhoneNum VARCHAR(11) NOT NULL,
StreetAddress VARCHAR(200) NOT NULL,
Sex GENDER NOT NULL,
ZIP VARCHAR(10) NOT NULL,
PRIMARY KEY(PID),
FOREIGN KEY(PID) REFERENCES Campers(CamperID),
FOREIGN KEY(PID) REFERENCES Counselors(CounselorID),
FOREIGN KEY(ZIP) REFERENCES Zip(ZIP)
);
DROP TABLE IF EXISTS Zip;
CREATE TABLE Zip (
ZIP VARCHAR(10) NOT NULL,
City TEXT NOT NULL,
State VARCHAR(2) NOT NULL,
PRIMARY KEY(ZIP)
);
DROP TABLE IF EXISTS Campers;
CREATE TABLE Campers (
CamperID VARCHAR(10) NOT NULL REFERENCES People(PID),
AgeGroup AGES NOT NULL,
CabinID VARCHAR(2) NOT NULL,
Bed BEDTYPES NOT NULL,
GroupID VARCHAR(3) NOT NULL,
PRIMARY KEY(CamperID),
FOREIGN KEY(CamperID) REFERENCES People(PID),
FOREIGN KEY(CabinID) REFERENCES Cabins(CabinID),
FOREIGN KEY(Bed) REFERENCES Beds(Bed),
FOREIGN KEY(GroupID) REFERENCES Groups(GroupID)
);
DROP TABLE IF EXISTS Counselors;
CREATE TABLE Counselors (
CounselorID VARCHAR(10) NOT NULL REFERENCES People(PID),
GroupID VARCHAR(3) NOT NULL,
CabinID VARCHAR(2) NOT NULL,
PRIMARY KEY(CounselorID),
FOREIGN KEY(GroupID) REFERENCES Groups(GroupID),
FOREIGN KEY(CabinID) REFERENCES Cabins(CabinID)
);
ERROR message for further clarification:
ERROR: relation "campers" does not exist
********** Error **********
ERROR: relation "campers" does not exist
SQL state: 42P01
There are more tables (obviously) which I can provide the create statements for, if needed.
You should really start here: Foreign key.
In the context of relational databases, a foreign key is a field (or
collection of fields) in one table that uniquely identifies a row of
another table.
What you are trying to do in your script is to create a circular link between People, Campers and Counselors. Having a Primary Key field also a Foreign Key mandates that IDs across all referenced tables are identical.
... and to create a Foreign Key the referenced table must already exist in the database. So you should start with the table that does not have any Foreign Keys and create tables that reference only those tables created previously. Alternatively you can create all tables without Foreign Keys and add them later, when all the tables are present.
... and to answer the question, Foreign Keys are never necessary, but they might help.

Foreign key referring to more than one primary key values(from one table) - Oracle SQL PLUS

I am still a beginner in SQL and i'm facing an issue. hope you can help me.
I have a table called Department where it has an attribute DEPARTMENT_NO as its primary key.
CREATE TABLE DEPARTMENT(
DEPARTMENT_NO INT NOT NULL,
NAME VARCHAR(25) NOT NULL,
LOCATION CHAR(15),
PRIMARY KEY(DEPARTMENT_NO));
I have another table called Doctor where it has an attribute DNUM as a foreign key referring to DEPARTMENT_NO :
CREATE TABLE DOCTOR(
DOCTOR_ID CHAR(9) NOT NULL,
DNUM INT NOT NULL,
NAME VARCHAR(20) NOT NULL,
DOB DATE,
SPECIALTY VARCHAR(20) NOT NULL,
SALARY INT,
CITY VARCHAR(15),
STREET VARCHAR(15),
START_DATE DATE,
PRIMARY KEY(DOCTOR_ID))
FOREIGN KEY(DNUM) REFERENCES DEPARTMENT(DEPARTMENT_NO));
A doctor can be working in one or two departments. So, if I have a doctor working in department 1 and 4 (the values for DNUM will include 1 and 4).
I initially chose the data type of DNUM to be INT(same as DEPARTMENT_NO data type). But INT is not ideal for multiple values.
What should the data type be? or what other solution i have if,for example, I run a query for returning the name of the doctors working in department 4.
The query should return all the names of doctors working in department 4(only) and the ones who work in multiple departments(including 4).
Thanks very much in advance and sorry for the long message.
The standard way to represent a "many to many" relationship is via a "junction" (aka "link") table:
CREATE TABLE DOCTOR_DEPARTMENT (
DOCTOR_ID INT REFERENCES DOCTOR(DOCTOR_ID),
DEPARTMENT_NO INT REFERENCES DEPARTMENT (DEPARTMENT_NO),
PRIMARY KEY (DOCTOR_ID, DEPARTMENT_NO)
);
Note the key on {DOCTOR_ID, DEPARTMENT_NO}, which ensures the same doctor cannot be connected to the same department twice.
It also implicitly creates a composite (aka. "concatenated") index on these fields in that order, which makes it very quick to find departments of a given doctor (via an index range scan). If you need to query in the opposite "direction" (for doctors of the given department), flip the order of fields. If you need both queries, then you'll need both indexes (i.e. you'll need to create one index explicitly).
Consider adding ORGANIZATION INDEX clause, if you need just one of these indexes.
You need an additional table called doctor_department
create table doctor_department
(doctor_id integer references doctor(doctor_id) not null,
dnum integer references department(dnum) not null
)
You can create another table with relation to these 2 tables
Say,
Create table Dept_Doctors(
ID int not null,
DOCTOR_ID char(9) not null,
DEPARTMENT_NO INT NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY(DEPARTMENT_NO) REFERENCES DEPARTMENT(DEPARTMENT_NO),
FOREIGN KEY(DOCTOR_ID) REFERENCES DOCTOR(DOCTOR_ID));
You can join the 3 tables and get the desired result.

oracle table creation

The following code gives me ERROR at line 3: ORA-00907: missing right parenthesis:
CREATE TABLE ORGANISATION(
ORG_REF VARCHAR(5),
POSTCODE VARCHAR(10) FOREIGN KEY,
TELEPHONE NUMBER FOREIGN KEY,
DESCRIPTION VARCHAR(30),
AGENCY_ID VARCHAR(5));
Line 3 code is very annoying because looking at the line there are no spelling mistakes and everything is in the right place.
That's not how you define a foreign key. A foreign key must know how to find it's partner.
Read here: http://www.techonthenet.com/oracle/foreign_keys/foreign_keys.php
Foreign key definition goes something like this:
CREATE TABLE ORGANISATION(
ORG_REF VARCHAR(5),
POSTCODE VARCHAR(10), --THIS WILL BE FOREIGN KEY
TELEPHONE NUMBER, --2nd FOREIGN KEY
DESCRIPTION VARCHAR(30),
AGENCY_ID VARCHAR(5),
FOREIGN KEY FK_POSTCODE
REFERENCES other_table (post_code),
FOREIGN KEY FK_TELEPHONE
REFERENCES other_table2 (phone)
);
UPDATE:
Additional Recommended Reading: http://mattgemmell.com/2008/12/08/what-have-you-tried/
Where to start?
You should be using varchar2 not varchar. Although they're currently identical the future behaviour of varchar is not guaranteed
Telephone number as a numeric field? A lot of phone numbers start with a 0. You're losing this. If you ever want to display it nicely you have to do some funky string manipulation on exit.
If your IDs are numbers then you should store them as a number.
There is rarely a situation where a table should not have a primary key.
A foreign key is designed to enforce referential integrity in the database. There should therefore be one or two more tables in this schema as a minimum.
A typical situation might be like this, which assumes that the same postcode,phone combination exists in agency.
CREATE TABLE ORGANISATION(
ORG_REF VARCHAR2(5),
POSTCODE VARCHAR2(10) ,
TELEPHONE VARCHAR2(50),
DESCRIPTION VARCHAR(30),
AGENCY_ID VARCHAR(5),
CONSTRAINT PK_ORGANISATION PRIMARY KEY ( org_ref ),
CONSTRAINT FX_ORGANISATION FOREIGN KEY
REFERENCES SOME_OTHER_TABLE(POSTCODE,PHONE)
);
If it were just a single column and not 2 you could reference it inline, something like the following:
create table organisation (
org_ref number(16) not null
, phone varchar2(5) not null constraint fk_organisation
references agency ( phone )
, constraint pk_organisation primary key ( org_ref )
);
However, I doubt very much that this'll work. A foreign key must reference a unique constraint. So, judging by your comments you must have a table agency with a unique constraint or primary key on phone, postcode.
I suspect your data-model is flawed; it sounds as though organisation inherits from agency.
I would remove the phone and postcode from agency and just do a join to get that information, if you're currently looking at the agency table:
select a.*, o.postcode, o.phone
from agency a
join organisation o
on a.agency_id = o.agency_id
where a.id = 12345
Further reading:
Examples
Documentation
CREATE TABLE ORGANISATION(
ORG_REF VARCHAR(5),
POSTCODE VARCHAR(10),
TELEPHONE NUMBER,
DESCRIPTION VARCHAR(30),
AGENCY_ID VARCHAR(5),
constraint pcodefk foreign key(POSTCODE) references postalcodetable(POSTALCODE),
constraint telefk foreign key(TELEPHONE) references telephonenumbers(TELEPHONE));

Foreign Key Problem in SQL

I just wanna ask coz I created a table with a column with two primary keys as shown below:
CREATE TABLE Parent(
Mother varchar(50) NOT NULL,
Father varchar(50) NOT NULL,
PRIMARY KEY(Mother, Father),
Organization varchar(50) NOT NULL
);
Then I am trying to create another table which will have a foreign key to the table shown above:
CREATE TABLE Child(
Name varchar(50) NOT NULL PRIMARY KEY,
Child_Mother varchar(50) REFERENCES Parent(Mother),
Child_Father varchar(50) REFERENCES Parent(Father),
Sibling varchar(50) NOT NULL
);
So I basically am trying to references two columns on the Child Table to a single column from the Parent table with two primary keys. Is this even possible? Thank you very much! :)
*Sample Tables only. But the actual are similar to this.
You haven't created a "table with a column with two primary keys", you've created one with a single composite primary key.
And what you are doing is indeed possible but not in the way you are doing it.
The problem is that you can have two Parent rows with the same Mother and different Father. But your foreign key relationship on Child_Mother will need a single instance of Mother in the Parent table otherwise it won't know which row it's referring to.
You can either have a combined column in the child which references the conbined primary key as you have it, or you can separate the Parent rows.
By that, I mean a parent table wouldn't normally put two people in a single row, it would normally have one row per person and the child would simply reference two separate rows in the Parent table, one for the mother and one for the father.
In terms of your actual tables:
create table Subject(
Subject_ID varchar(50) NOT NULL,
Subject_Description varchar(50) NOT NULL,
PRIMARY KEY(Subject_ID, Subject_Description),
Subject_SID int references Student(Student_ID),
Unit varchar(50) NOT NULL
)
This is not actually normalised since the subject description almost invariable depends on the subject ID. I think the primary key should probably just be on subject ID. By all means have another index on subject description but it shouldn't be part of the primary key.
I'm still not sure that you understand what I'm saying so I'll try to clarify. The line:
PRIMARY KEY(Subject_ID, Subject_Description)
does not make two primary keys, it makes a single primary key made up of the two columns (id and description). Because of that, it is possible to have two rows with the same ID provided that the description is different.
So a foreign key reference to the ID column is not possible. Let's say you had two rows:
ID Subject Other
-- ------- ---------
7 Maths blah blah
7 Physics yada yada
and then tried to add to the schedule table a row with Schedule_SID set to 7. That will choke because the DBMS wouldn't know which 7 you're referring to. So it shouldn't even let you set up that foreign key constraint because the target column isn't unique.
Try this one -
CREATE TABLE Child(
Name varchar(50) NOT NULL PRIMARY KEY,
Child_Mother varchar(50),
Child_Father varchar(50),
Sibling varchar(50) NOT NULL,
Foreign Key (Child_Mother, Child_Father) references Parent(Mother, Father)
);
Since you are creating a primary key which consists of two columns, you need to refer to them together.
What paxdiablo said is true. You are creating a composite primary key which consists of two columns. I would suggest you to use a Surrogate Primary Key.
Edit
CREATE TABLE Child(
id bigint NOT NULL auto_increment, // an "id" column
Name varchar(50) NOT NULL unique,
age int not null,
primary key (id) // "id" column is being declared as surrogate primary key
);
Second Edit
create table Subject(
id int not null,
Subject_ID varchar(50) NOT NULL,
Subject_Description varchar(50) NOT NULL,
PRIMARY KEY(id),
Subject_SID int references Student(Student_ID),
Unit varchar(50) NOT NULL
);
ALTER TABLE Subject ADD CONSTRAINT subject_unique UNIQUE (Subject_id, Subject_Description);
create table Schedule(
Day_MTWTHF varchar(50) NOT NULL,
TIME_HH varchar(50) NOT NULL,
subject_id int not null, -- my newly added column
Schedule_SID int references Student(Student_ID),
foreign key(subject_id) references Subject(id)
);
I'd say your choice of primary key is poor for the Parent table. It looks like you're using names. What happens if you've got two seperate couples whose names match up? John & Jane Smith with Alice and Bob for children, under your design, would also be the same John & Jane Smith from the next town over who've got Charlie and Dolores for kids, even though in reality they're completely unrelated.
Names are invariably a bad choice for keys, as names can be repeated. Using something guaranteed to be unique, such as an auto-incrementing integer, would be far safer, and would allow you to keep the J&J Smith from Springfield seperate from the J&J Smith from Shelbyville.