what is FOREIGN KEY is for? - sql

let's say i have 2 tables:
Department(depNum)
Worker(id,deptNum) - key should be id
now i want dept to reference an existing value in Department.
so i write in create table:
CREATE TABLE Worker(
id integer primary key,
dept integer references Department);
my question is, i've seen in many examples that you also put foreign key with the references statement. i don't understand what is primary key for.
does it mean that dept will be also a key on Worker?
thank you

From Wikipedia:
A primary key is a combination of columns which uniquely specify a
row. It is a special case of unique keys. . . . Primary keys were
added to the SQL standard mainly as a convenience to the application
programmer.
You cannot reference a record in a table without a primary key. A foreign key lets you reference a record in another table within an individual record. This foreign key is usually referencing the primary key in the foreign table.

This post has a lot of great information. In particular, check out the highest ranked answer for a bullet list of do's and do not's.
What's wrong with foreign keys?
This post gives a pretty decent explanation, given the poster's
original example:
What will these foreign keys do?

Let's say that each worker can only work in one department at any one time.
So each department has its own unique ID. This is the department's primary key because two departments should never have the same id.
Now, each individual worker must be tracked so they are also assigned their own unique ID. This is their primary key. You need to link the worker to the department that they work in and since they can only work in one department at a time, you can have their department as a foreign key. The foreign key in the worker table is linked to the ID of the department table.
This has more information: http://www.1keydata.com/sql/sql-foreign-key.html

You have two tables:
PLAYER,
primary key (unique) PK_player_id
player_name
foreignt key to TEAM.team_id FK_team_id
TEAM
primary key (unique) PK_team_id
team_name
Every PLAYER is in exact one TEAM.
The PLAYER has a FOREIGN-KEY to the TEAM (FK_team_id). Also you can delete the TEAM, which will delete all player in it cascading (if configured).
Now you can't create a player without an existing TEAM, because the database ensures this.
EDIT:
Didn't you ask for the foreign key?
The primary key is one or more than one column, which will identify on datarow within your database. If jou want to create a foreign key, you have to use a column or more than one column) which is unique.
In my example, there is a unique key (the primary key) for every table, because the name may change. To identify the 'target' of the foreign key, it has to be unique. so it is liklye to use the prmary key of the second table. (TEAM.PK_team_id)

I am not clear, the requirement should be
Department(dept)
Worker(id,dept) - key should be id
which means dept is the primary key in Department and foreign key in worker.
the foreign key is not unique in worker table but it is unique in Department Table.
The worker table cannot have some unknown department which is not defined in the Department.
Did I make sense ?

To ensure the integrity of the tables, not allowing you to enter values in the table (Worker) without referencing an existing row (at Department)

According to the SQL-92 Standard:
A foreign key (FK) may reference either a PRIMARY KEY or a UNIQUE CONSTRAINT. In the case of a PRIMARY KEY, the referenced columns may be omitted from the foreign key declaration e.g. the following three are all valid:
CREATE TABLE Department ( Department INTEGER NOT NULL PRIMARY KEY, ...);
CREATE TABLE Worker (dept INTEGER REFERENCES Department, ...);
CREATE TABLE Department ( Department INTEGER NOT NULL PRIMARY KEY, ...);
CREATE TABLE Worker (dept INTEGER REFERENCES Department (dept), ...);
CREATE TABLE Department ( Department INTEGER NOT NULL UNIQUE, ...);
CREATE TABLE Worker (dept INTEGER REFERENCES Department (dept), ...);
The following is not valid:
CREATE TABLE Department ( Department INTEGER NOT NULL UNIQUE, ...);
CREATE TABLE Worker (dept INTEGER REFERENCES Department, ...);
...because the referenced columns involved in the foreign key must be declared.
When declaring a simple (single-column) FK in-line the FOREIGN KEY keywords are omitted as above.
A composite (multiple-column) cannot be declared in-line and a simple FK need not be declared in-line: in these cases, the referencing column(s) AND the FOREIGN KEY keywords are required (the rules for the referenced columns remain the same as stated earlier) e.g. here are just a few examples:
CREATE TABLE Department ( Department INTEGER NOT NULL PRIMARY KEY, ...);
CREATE TABLE Worker (dept INTEGER, FOREIGN KEY (dept) REFERENCES Department, ...);
CREATE TABLE Department ( Department INTEGER NOT NULL UNIQUE, ...);
CREATE TABLE Worker (dept INTEGER, FOREIGN KEY (dept) REFERENCES Department (dept), ...);
CREATE TABLE DepartmentHistory
(
dept INTEGER NOT NULL,
dt DATE NOT NULL,
PRIMARY KEY (dt, dept),
...
);
CREATE TABLE Worker
(
dept INTEGER NOT NULL,
dept_dt DATE NOT NULL,
FOREIGN KEY (dept_dt, dept) REFERENCES DepartmentHistory,
...
);

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.

SQL Server: why are two foreign keys allowed on a column referencing to single column?

Why does SQL Server allow this?
create table dbo.tab1
(
id int primary key
)
create table dbo.tab2
(
id int constraint first_name references tab1(id),
constraint second_name foreign key (id) references tab1(id)
)
Here's an example that might clarify this a bit.
I have a person table which defines all of the people in the system. I then have a marriage table. A marriage is defined as a pairing of 1 Husband and 1 Wife, and both of these need to be valid entries in the Person table.
create table dbo.Person
(
id int primary key
)
create table dbo.Marriage
(
id int constraint Husband references tab1(id),
id2 int constraint Wife foreign key (id) references tab1(id)
)
Example was for clarity. Please forgive me for any political or cultural assumptions that may have gone into it.
Yes. This is quite interesting functionality wise. See if you are using parent child concept then it's helpful.
Example: If you have customer and dbo.Customer table. The customer distribute the commission after some recharge. So when you relate Customer to its parent chain you need the same column of customer table as foreign key twice.

SQL Constraint on join table

I have four tables in a PostgreSQL database:
Company
User (with a foreign key column company_id)
Location (with a foreign key column company_id)
UserLocations (an association table, with foreign key columns user_id and location_id)
Essentially:
a company has many users and locations
a user belongs to a company and has many locations
a location belongs to a company and has many users
I want to know if there is a way for the database to constrain entries in the UserLocations association table such that the referenced user and location must have an identical company_id value. I don't want a user from company A to have a location from company B.
I can check this at my application layer (rails) but would be interested in making this a hard database level constraint if the option exists.
One way you can accomplish this is with foreign key references and redundancy.
So, the UserLocations table would have a UserId, LocationId, and CompanyId. It would then have the following foreign key relationships:
foreign key (UserId, CompanyId) references Users(UserId, CompanyId)
foreign key (LocationId, CompanyId) references Locations(LocationId, CompanyId)
Of course, you have to declare Users(UserId, CompanyId) and Locations(LocationId, CompanyId) as unique keys for the reference. This is a bit redundant, but it does guarantee the matching to company without creating triggers.
Overlapping foreign key constraints are your friend.
create table company (
company_id integer primary key
);
-- Reserved words include "user". Better to use identifiers that
-- are not reserved words.
create table "user" (
user_id integer primary key,
company_id integer not null references company (company_id),
-- Unique constraint lets this be the target of a foreign key reference.
unique (user_id, company_id)
);
create table location (
location_id integer primary key,
company_id integer not null references company (company_id),
unique (location_id, company_id)
);
create table user_location (
user_id integer not null,
location_id integer not null,
company_id integer not null,
-- Not sure what your primary key is here.
-- These foreign keys overlap on the column "company_id", so there
-- can be only one value for it.
foreign key (user_id, company_id) references "user" (user_id, company_id),
foreign key (location_id, company_id) references location (location_id, company_id)
);

violated - parent key not found error

I have the following error appearing:
INSERT INTO GroupMembers VALUES ('Goldfrat', 'Simon Palm')
*
ERROR at line 1:
ORA-02291: integrity constraint (SHAHA1.IAM_IS_GROUP_FK) violated - parent key
not found
The constraint in the GroupMembers table is:
CONSTRAINT iam_is_group_fk FOREIGN KEY(is_group) REFERENCES Members(group_name)
The Members Table looks like this:
CREATE TABLE Members (
group_name VARCHAR2(40),
CONSTRAINT g_id_pk PRIMARY KEY(group_name),
CONSTRAINT m_group_name_fk FOREIGN KEY(group_name) REFERENCES Artist(artistic_name));
All of the tables are created fine until it comes to creating the GroupMembers table. Anyone have any ideas? I've been scratching for quite a while.
The problem is that
CONSTRAINT iam_is_group_fk FOREIGN KEY(is_group) REFERENCES Members(group_name); references the table Members on the group_name field.
This means that the field is_group on the table GroupMembers must have an identical value on the table Members and group_name field.
In my opinion, this is bad practice.
First of all, you should have a primary key field on the table GroupMembers. You should not store the names of the group members in the table GroupMembers, but their corresponding id from the table Members.
Also, the table Members should look something like this:
CREATE TABLE Members (
member_id NUMBER PRIMARY KEY
member_name VARCHAR2(40),
CONSTRAINT g_id_pk PRIMARY KEY(member_id),
CONSTRAINT m_group_name_fk FOREIGN KEY(group_name) REFERENCES Artist(artistic_name));
Then on the table GroupMembers, I suppose you want to associate some members to their set of groups and back, so you should do something like this:
CREATE TABLE GroupMembers (
member_id NUMBER,
group_id NUMBER
)
CONSTRAINT iam_is_member_fk FOREIGN KEY(member_id) REFERENCES Members(member_id);
CONSTRAINT iam_is_member_fk FOREIGN KEY(group_id) REFERENCES Groups(group_id);
Supposing that you have a table Groups containing all the group details, with the primary key stored as number , and name group_id.
Always remember that each table must have a primary key. It is good practice for this key to be a number.
So by having member_id in Members, group_id in Groups, you can create a many-to-many relationship in GroupMembers. Also, put a unique index on this table so you don't have duplicates ( the same member associated with the same id several times ).
Look at this example linking users to roles. It is the same case:
error is
you have to use same column name which is defined in reference table
i.e
CONSTRAINT m_group_name_fk FOREIGN KEY(group_name) REFERENCES Artist(group_name)
That group_name should be define as primary key in Artist Table.
Order in which you are insert is the reason for the error.
Members(group_name) does not contain Goldfrat. If this is not true then it's not there in the table Artists.

Creating Tables

Suppose you have the following database:
Person(ssn NUMERIC(9), name VARCHAR(40), gender CHAR(1)), ssn is primary key
Organization(org_code CHAR(4), budget INTEGER, org_name VARCHAR(60)), org_code is primary key
Person_Organization(ssn, org_code), both columns are the primary key.
Are the keys in the person_organization table considered foreign keys or primary keys? I am stuck on how to create this table. Have tried looking in my textbooks but cannot find information about it. I don't know if they are supposed to be foreign keys that reference the primary keys or if I should just do this
CREATE TABLE person_organization(ssn NUMERIC(9), org_code VARCHAR(60));
Any suggestions would be greatly appreciated.
Thanks.
The simple answer is that they're both.
ssn, org_code should be the primary key of person_organization.
ssn should be a foreign key back into person and org_code should by a foreign key back into organization.
To separate myself from northpole's answer I don't actually agree with the surrogate key argument in this case it doesn't seem to be needed as it won't be used anywhere else.
Unfortunately the problem with this (good) solution to the many to many relationship is that it's often needed to have two unique keys on a table, ssn, org_code and org_code, ssn and choose one as the primary key.
As you're using Oracle the create table syntax would be
create table person_organization
( ssn number(9)
, org_code varchar2(60)
, constraint person_organization_pk primary key (ssn, org_code)
, constraint person_organization_ssn_fk foreign key ( ssn )
references person ( ssn )
, constraint person_organization_oc_fk foreign key ( org_code )
references organization ( org_code )
);
In your original table creation script you had ssn as numeric(9), which should by number(9). You may want to consider not restricting the size of this data type. You also had org_code as a varchar, this should probably be a varchar2.
Tech on the Net is a really good resource for learning syntax.
I would suggest adding a unique, auto incrementing primary key to PERSON_ORGANIZATION (called something like po_id) as well as the two FOREIGN keys of ssn and org_code. You can also make those two unique if you want. From my experience, I like to have almost every table have it's own unique/auto key (unless it is a lookup table or audit table (and possibly others)).
They're both.
For the person_organization table you would have a compound primary key that consisted of the two columns. Each is separately a foreign key to another table.
For normal database design they should reference the primary keys in the other tables and these constraints enforce the validity of the data in the database.
They are foreign keys.
You've listed "both columns are the primary key" but I don't think they are.
The table does not have a primary key.
The combination of the two fields is certainly acting as a proxy for a primary key, doing things like making sure entries are uniquely identified and thus acting together as a unique identifier but that is a bit different.
I would also recommend adding a separate primary key field for consistency with the structure of others tables. As with other tables I recommend always using either id [my favorite] or tablename_id
This is the basic idea, you need to provide proper datatype for each field
CREATE TABLE Persons (
ssn int(9) NOT NULL PRIMARY KEY,
name varchar(40),
gender CHAR(1)
)
CREATE TABLE Organization (
org_code CHAR(4)NOT NULL PRIMARY KEY,
budget INTEGER,
org_name VARCHAR(60)
)
CREATE TABLE Person_Organization (
ssn int FOREIGN KEY REFERENCES Persons(ssn),
org_code CHAR FOREIGN KEY REFERENCES Organization(org_code)
)