Foreign Key References Two Tables - sql

I'm currently working on a database and I came across a new problem to me. The entities involved are Universe, Competition, Game, Pot. Here are the SQL files to create the tables:
CREATE TABLE Universe (
id int NOT NULL IDENTITY PRIMARY KEY,
history nvarchar (max),
creation_date date
);
CREATE TABLE Pot (
pot_name nvarchar(100),
universe_id int FOREIGN KEY REFERENCES Universe(id),
pot_description nvarchar(100),
media_description nvarchar(100),
is_official_pot bit
PRIMARY KEY (pot_name, universe_id)
);
CREATE TABLE Competition (
universe_id int NOT NULL FOREIGN KEY REFERENCES Universe(id),
compt_name nvarchar(100) NOT NULL,
alias nvarchar(100),
history nvarchar(max),
rules nvarchar (max),
winner_id nvarchar(100) FOREIGN KEY REFERENCES RaulUser(username),
edition int NOT NULL,
is_official_competition bit NOT NULL,
PRIMARY KEY (universe_id, compt_name, edition)
);
CREATE TABLE Game (
id int NOT NULL IDENTITY PRIMARY KEY,
pot_name nvarchar (100) NOT NULL,
universe_id int NOT NULL,
competition_name nvarchar(100) NOT NULL,
competition_edition int NOT NULL,
competition_round int NOT NULL,
home_raul_u_username nvarchar (100) FOREIGN KEY REFERENCES RaulUser(username) NOT NULL,
home_team nvarchar (100) NOT NULL FOREIGN KEY REFERENCES Team(team_name),
home_score int,
away_raul_u_username nvarchar (100) NOT NULL FOREIGN KEY REFERENCES RaulUser(username),
away_team nvarchar (100) NOT NULL FOREIGN KEY REFERENCES Team(team_name),
away_score int,
is_over bit NOT NULL,
played_date date,
FOREIGN KEY (universe_id, competition_name, competition_edition) REFERENCES Competition(universe_id, compt_name, edition),
FOREIGN KEY (universe_id, pot_name) REFERENCES Pot(universe_id, pot_name)
);
The problem starts with this last table (Game), as I can't use universe_id as a Foreign Key for different tables. What's the best approach to solving this? Creating an M:M table Game_Pot?
I only need to record the Pot of each Game because Pots change overtime and I don't want to lose that data.
Sorry for the long post and thank you all in advance :)

The only problem that I see is in the definition of table Game:
FOREIGN KEY (universe_id, pot_name) REFERENCES Pot(universe_id, pot_name)
Ordering of columns matters. The primary key of table Pot is (pot_name, universe_id), so you need to swap the columns in the foreign key, like so:
FOREIGN KEY (pot_name, universe_id) REFERENCES Pot(pot_name, universe_id)
Note that having identity (or the-like) primary key in every table might simplify your design: it would allow you to reduce the number of columns in the children tables, and to use single-column foreign keys. Meanwhile, you can still enforce uniqeness on columns tuples in the parent tables with unique constraints.

Related

Creating SQL database. with multiple primary and foreign keys

I'm currently working through an assignment that is asking me to create a SQL database using SQL Server Express. This is what it's asking for:
CREATE DATABASE USING SQL
And this is the code I have tried running;
CREATE DATABASE db_Library
Go
USE db_Library
CREATE TABLE tbl_library_branch
(
library_branch_branch_id INT PRIMARY KEY NOT NULL IDENTITY (1,1),
library_branch_branch_name VARCHAR(50) NOT NULL,
library_branch_address VARCHAR(50) NOT NULL
);
CREATE TABLE tbl_publisher
(
library_publisher_publisher_name VARCHAR(50) PRIMARY KEY NOT NULL,
library_publisher_address VARCHAR(50) NOT NULL,
library_publisher_phone INT NOT NULL
);
CREATE TABLE tbl_books
(
library_books_book_id INT PRIMARY KEY NOT NULL IDENTITY (1,1),
library_books_title VARCHAR(50) NOT NULL,
library_books_publisher_name VARCHAR(50) NOT NULL CONSTRAINT fk_library_books_publisher_name FOREIGN KEY REFERENCES tbl_publisher(library_publisher_publisher_name) ON UPDATE CASCADE ON DELETE CASCADE
);
CREATE TABLE tbl_book_authors
(
library_book_authors_book_id INT NOT NULL CONSTRAINT fk_library_book_authors_book_id FOREIGN KEY REFERENCES tbl_books(library_books_book_id) ON UPDATE CASCADE ON DELETE CASCADE,
library_book_authors_author_name VARCHAR(50) NOT NULL
);
CREATE TABLE tbl_book_copies
(
library_book_copies_book_id INT NOT NULL CONSTRAINT fk_library_book_copies_book_id FOREIGN KEY REFERENCES tbl_books(library_books_title),
library_book_copies_branch_id INT NOT NULL,
library_book_copies_number_of_copies INT NOT NULL
);
CREATE TABLE tbl_book_loans
(
library_book_loans_book_id INT NOT NULL,
library_book_loans_branch_id INT NOT NULL,
library_book_loans_card_no INT NOT NULL,
library_book_loans_date_out INT NOT NULL,
library_book_loans_date_due INT NOT NULL
);
CREATE TABLE tbl_borrower
(
library_borrower_card_no INT PRIMARY KEY NOT NULL IDENTITY (1,1),
library_borrower_name VARCHAR(50) NOT NULL,
library_borrower_address VARCHAR(50) NOT NULL,
library_borrower_phone VARCHAR(50) NOT NULL
);
Using the library "Books" as an example it looks like I need to have BoodID as a primary key and Title as a primary key, but you can't have more than one primary key per table..
Then I have to take BookID from the Book_Copies table and the Book_Loans table connect to the primary key of Title in Books?
I'm beyond stuck at this point and would appreciate any resources you think could help.
There is no need to be so verbose. I think you want something more like this (for two tables):
CREATE TABLE tbl_publisher (
publisher_id int IDENTITY(1, 1) PRIMARY KEY,
publisher_name VARCHAR(50) NOT NULL UNIQUE,
address VARCHAR(50) NOT NULL,
phone INT NOT NULL
);
CREATE TABLE books (
book_id INT IDENTITY (1,1) PRIMARY KEY,
title VARCHAR(50) NOT NULL UNIQUE,
publisher_id INT NOT NULL CONSTRAINT fk_books_publisher__id FOREIGN KEY REFERENCES tbl_publisher(publisher_id) ON UPDATE CASCADE ON DELETE CASCADE
);
Notes:
Stick with synthetic primary keys for all the tables. That is, identity columns.
Other columns can be declared to be unique. That is fine.
I type quite fast. And yet I would quickly wary of typing library_book_ over and over. Such repetition just makes it harder to write and read queries.

error: there is no unique constraint matching given keys for referenced table "incident"

I know that this question has been already answered a million of times, but I couldn't find any solution. Well I have these three tables on postgres sql.
CREATE TABLE user_account (
id SERIAL not null,
firstName VARCHAR(60) not null,
lastName VARCHAR(60) not null,
password VARCHAR(150) not null,
email VARCHAR(40) not null UNIQUE,
isVolunteer BOOLEAN,
complete BOOLEAN,
CONSTRAINT pk_user PRIMARY KEY (id));
CREATE TABLE incident (
id SERIAL not null,
patientId INTEGER not null,
incidentTime VARCHAR(10) not null,
latitude NUMERIC not null,
longitude NUMERIC not null,
city VARCHAR(60) not null,
state VARCHAR(60),
country VARCHAR(60),
complete BOOLEAN,
CONSTRAINT pk_incident PRIMARY KEY (id, patientId),
CONSTRAINT fk_incident FOREIGN KEY (patientId)
REFERENCES user_account (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE);
CREATE TABLE incident_has_volunteer (
incidentId INTEGER not null,
volunteerId INTEGER not null,
incidentTime VARCHAR(10) not null,
complete BOOLEAN,
CONSTRAINT pk_incident_has_volunteer PRIMARY KEY (incidentId, volunteerId),
CONSTRAINT fk_volunteer FOREIGN KEY (volunteerId)
REFERENCES user_account (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT fk_incident FOREIGN KEY (incidentId)
REFERENCES incident (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE);
When I try to create the table incident_has_volunteer it throws the error there is no unique constraint matching given keys for referenced table "incident".
I tried to add on the third table and the patientId as a foreign key from table incident table but with no luck. I can't understand why it throws this error even if I have already set the primary keys on the incident table.
I'm not an expert in postgres, but I believe that the problem is while fk_incident is referencing incident.id, incident's primary key is made of id + patientId. Since incident.id is guaranteed to be unique only in combination with patientId, there's no way to ensure referential integrity.
I believe that if you add a unique constraint to incident.id (I'm assuming that it would be unique), your foreign key will be legal.
Very simply - one table of primary key acts as a foreign key for another table, so you must ensure that both key is referenced or not.
Simply you will not assign foreign key to the column of another table which does not have primary key. this is called as RDBMS.
Thanks

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.

Use a common table with many to many relationship

I have two SQL tables: Job and Employee. I need to compare Job Languages Proficiencies and Employee Languages Proficiencies. A Language Proficiency is composed by a Language and a Language Level.
create table dbo.EmployeeLanguageProficiency (
EmployeeId int not null,
LanguageProficiencyId int not null,
constraint PK_ELP primary key clustered (EmployeeId, LanguageProficiencyId)
)
create table dbo.JobLanguageProficiency (
JobId int not null,
LanguageProficiencyId int not null,
constraint PK_JLP primary key clustered (JobId, LanguageProficiencyId)
)
create table dbo.LanguageProficiency (
Id int identity not null
constraint PK_LanguageProficiency_Id primary key clustered (Id),
LanguageCode nvarchar (4) not null,
LanguageLevelId int not null,
constraint UQ_LP unique (LanguageCode, LanguageLevelId)
)
create table dbo.LanguageLevel (
Id int identity not null
constraint PK_LanguageLevel_Id primary key clustered (Id),
Name nvarchar (80) not null
constraint UQ_LanguageLevel_Name unique (Name)
)
create table dbo.[Language]
(
Code nvarchar (4) not null
constraint PK_Language_Code primary key clustered (Code),
Name nvarchar (80) not null
)
My question is about LanguageProficiency table. I added an Id has PK but I am not sure this is the best option.
What do you think about this scheme?
Your constraint of EmployeeId, LanguageProficiencyId allows an employee to have more than one proficiency per language. This sounds counterintuitive.
This would be cleaner, as it allows only one entry per language:
create table dbo.EmployeeLanguageProficiency (
EmployeeId int not null,
LanguageId int not null,
LanguageLevelId int not null,
constraint PK_ELP primary key clustered (EmployeeId, LanguageId)
)
I don't see the point of table LanguageProficiency at the moment.
Same applies to the Job of course. Unless you would like to allow a "range" of proficiencies. But assuming that "too high proficiency" does not hurt, it can easilly be defined through a >= statement in our queries.
Rgds

Foreign keys issue

I have a table created using the query
CREATE TABLE branch_dim (
branch_id numeric(18,0) NOT NULL,
country_name varchar(30),
island_name char(30),
region_name varchar(30),
branch_name varchar(30),
region_manager varchar(30),
marketing_manager varchar(30),
branch_manager varchar(30),
promoter_main varchar(30),
promoter_other varchar(30),
PRIMARY KEY (branch_id,island_name)
) ON branch_dim_scheme(island_name)
Now I have another table
CREATE TABLE order_fact (
branch_id numeric(18,0) NOT NULL,
product_id numeric(18,0) NOT NULL,
order_id numeric(18,0) NOT NULL,
day_id numeric(18,0) NOT NULL,
FOREIGN KEY (branch_id) REFERENCES branch_dim (branch_id),
)
First query has partition in it that is why I have 2 primary keys. Now if I run the second query I am getting the error
"There are no primary keys or
candidate keys in the referenced table
'branch_dim' that matches the
reference column list in the foreign
key 'FK_order_fac_branc_10234AD'"
What might be the problem ?
You've defined the primary key on branch_dim as a composite primary key made up of branch_id and island_name. When you create order_fact, you're trying to reference only branch_id as your foreign key.
Your table has a composite primary key :
CREATE TABLE branch_dim (
PRIMARY KEY (branch_id,island_name)
Hence, any foreign key reference to that table also must use both elements for its foreign key (you need to reference the key, the whole key, and nothing but the key - so help you Codd :-):
CREATE TABLE order_fact (
branch_id numeric(18,0) NOT NULL,
island_name char(30),
product_id numeric(18,0) NOT NULL,
order_id numeric(18,0) NOT NULL,
day_id numeric(18,0) NOT NULL,
FOREIGN KEY (branch_id, island_name)
REFERENCES branch_dim (branch_id, island_name)
Word of advice: for anything longer than 5 character or so, I would never use CHAR(x) as the data type - this will create a field that is always 30 characters long - whether you store that many chars in it or not. If you store less, the value is padded with spaces to the defined length (30 chars).
For anything larger than 5 or so characters, I would recommend to always use VARCHAR instead !
Same goes for numeric(18,0) : for an ID field, I would always use INT - much nicer, cleaner, smaller, just plain better!
You need to make the primary key of branch_dim just branch_id and add an index on island_name. Also, are you branch_ids really numeric(18, 0)? If so I would make a surrogate primary key (something that can be auto incremented, int or bigint, identity).
As it is, your primary key (and thus clustered index) is very wide. This will degrade performance and I'm guessing, in your scenario, fragment your clustered index (bad).
I solved the problem by making the primary key field (branch_id) as NONCLUSTERED and UNIQUE and made the island_name field as and so i had only one primary key and my partition key is island_name. This solved my problem. Thanks all for the help..