Foreign keys issue - sql

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..

Related

Foreign Key References Two Tables

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.

Missing Keyword in SQL Code on Foreign Keys unable to create the table

Trying to create a table with an SQL code, but I'm getting an error:
Missing keyword
in regards to the foreign key.
CREATE TABLE Staff
(
staffID VARCHAR(5) NOT NULL,
name VARCHAR(50),
position VARCHAR(30),
branchID VARCHAR(5),
PRIMARY KEY (staffID),
FOREIGN KEY (branchID) REFERENCES Branch ON UPDATE CASCADE
);
Unlike other RDBMS (such as MySQL for example), Oracle does not support the ON UPDATE clause in foreign keys. You would just need to remove that part of the declaration.
Try:
CREATE TABLE Staff (
staffID VARCHAR(5) NOT NULL,
name VARCHAR(50),
position VARCHAR(30),
branchID VARCHAR(5),
PRIMARY KEY (staffID),
FOREIGN KEY (branchID) REFERENCES Branch(branchID) --ON UPDATE CASCADE
);
Demo on DB Fiddle
The logic behind this Oracle behavior is that the referred column is not supposed to change, since it must be PRIMARY KEY (or a UNIQUE column). I believe that this limitation makes sense... they just don't want to give users enough rope to hang themselves with.

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: 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

creating table having foreign key that reference another table

I am using PGAdminIII database.
I have one table named STOCKREGISTER which contains composite primary key consisting of three fields ie stockregisterId,applicationId and date.
I have to create another table STOCK which has a foreignkey field that reference the field stockregisterId of STOCKREGISTER.If I am trying to create STOCK table,an error message is shown.The error message is "there is no unique contraint matching keys for referenced table STOCKREGISTER".What another step I have to take next
this first table
CREATE TABLE stock_register
(
stock_register_id bigint NOT NULL,
application_id bigserial NOT NULL,
production_date date NOT NULL,
opening_bal bigint DEFAULT 0,
quantity_produced bigint,
total_quantity bigint
CONSTRAINT primarykey PRIMARY KEY (stock_register_id, application_id, production_date),
CONSTRAINT "foreignKey" FOREIGN KEY (application_id)
REFERENCES application (application_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
below is second table.Here I cannot make stock_register_id as a foreign key
CREATE TABLE Stock
(
stock_id bigint NOT NULL,
stock_register_id bigint,
dimension bigserial NOT NULL,
CONSTRAINT "stockid" PRIMARY KEY (stock_id)
)
I guess that syntax should be:
CREATE TABLE Stock
(
stock_id bigint NOT NULL,
stock_register_id bigint,
dimension bigserial NOT NULL,
CONSTRAINT "stockid"
FOREIGN KEY (stock_id)
REFERENCES stock_register (stock_register_id)
)
CREATE TABLE Stock
(
stock_id bigint NOT NULL,
stock_register_id bigint,
dimension bigserial NOT NULL,
CONSTRAINT primaryKey PRIMARY KEY (stock_id),
CONSTRAINT foreignKey FOREIGN KEY(stock_register_id)
REFERENCES stock_register (stock_register_id)
)
That should be everything you need. You'll also have to make sure the DB table engines, collations and charsets match up when using Foreign Keys.
For the unique constraint issue, there doesn't seem to be a problem with your stock_register_id PK in the stock_register table. Based on the name STOCKREGISTER in the error message I suspect it wasn't finding the table stock_register in your second Create statement.
What is a foreign key? A pointer to a specific record in another table.
How is a specific record in stock_register identified according to your DDL? By the unique combination of (stock_register_id, application_id, production_date).
Therefore stock_register_id = 1 could appear on a thousand different records so long as application_id and production_date are different.
Therefore, if all you have is a stock_register_id, there is no way to know which stock_register record it is pointing to and therefore no way for the DBMS to enforce the foreign key.
You must either add application_id and production_date to the stock table and make all three columns together the FK to the composite key on stock_register, or you must remove application_id and production_date from the PK on stock_register so the FK and PK columns match.