SQL Server Foreign Key - sql

I'm trying to create this database with the following relations in SQL Server and I get this error:
Msg 1776, Level 16, State 0, Line 11
There are no primary or candidate keys in the referenced table 'Consumable' that match the referencing column list in the foreign key 'FK_Recipe_Ingredie__59FA5E80'.
Msg 1750, Level 16, State 0, Line 11
Could not create constraint. See previous errors.
What am I doing wrong?
Here's my code;
CREATE TABLE Consumable
(
c_ID int NOT NULL,
Name varchar(32) NOT NULL,
Amount int,
Unit varchar(8) NOT NULL CHECK (unit IN ('ml', 'g', 'pieces', 'unknown')),
CONSTRAINT PK_Consumable PRIMARY KEY (c_ID, Name)
)
CREATE TABLE Recipe
(
Name varchar(64) PRIMARY KEY NOT NULL,
Type varchar(32),
Description varchar(512),
IngredientsID int NOT NULL FOREIGN KEY REFERENCES Consumable(c_ID) ON DELETE CASCADE
)
CREATE TABLE Kitchen
(
K_ID int PRIMARY KEY NOT NULL IDENTITY,
IngredientsID int FOREIGN KEY REFERENCES Consumable(c_ID) ON DELETE CASCADE
)

Read the error message!
It's pretty clear: the foreign key you're trying to set up from Recipe.IngredientsID doesn't reference the primary key of your target table (Consumable - primary key is (c_ID, Name) - not just c_ID ....)
To fix this: you must reference the whole compound PK on your target table (e.g. you must have both columns of PK_Consumable in your child table in order to reference it
CREATE TABLE Recipe
(
Name varchar(64) PRIMARY KEY NOT NULL,
Type varchar(32),
Description varchar(512),
IngredientsID int NOT NULL,
IngredientsName varchar(32) NOT NULL,
CONSTRAINT FK_Recipe_Consumable
FOREIGN KEY (IngredientsID, IngredientsName)
REFERENCES Consumable(c_ID, Name) ON DELETE CASCADE
)
Any foreign key can only ever reference the WHOLE primary key of a parent table - or a unique constraint (again: all columns involved in that unique constraint). You cannot just simply refer to an arbitrary column (or set of columns) in your parent table.

Your Pk is a composite PK and so c_id is not necessarily unique and thus cannot be used in an FK relationship.
You have several choices depending that you had. If you will not have multiple of c_id in the consumables table than you can create a unique index on it and you should be able to create the Fk. BUt in that case really why are you using a compositer OK? The other choice you have in this situation is to make just the c_id the PK and then put a unique index on Name. Never use a composite PK if you don't have to.
If the C_id will into be unique in the Consumable table, then the only choice you have is to add the name column to the Other tables. You would of course have to give it a different name in Recipe since it has a different name.
Ingredients_id doesn't make sense in the recipe table as you are going to have more than one ingredient in a recipe. You should have a child table that contains recipe ingredients.
And On Delete Cascade is a poor choice as well. Very bad thing to do to a nice innocent database. Do you really want to delete the recipes you are out of an ingredient? I don't think so.

Related

Sql creating table consisting of keys from other tables

this is probably a simple question but I am quite new to SQL and databases, so I have been following this site: https://www.postgresqltutorial.com/postgresql-foreign-key/ to try and create a table that consist of primary keys from other tables.
Here I have the structure of the database in an excel overview. With colors showing the relations. i am having problems with the One-To-Many tables. As I get the same error every time "ERROR: column "id" referenced in foreign key constraint does not exist
SQL state: 42703".
The SQL query:
DROP TABLE IF EXISTS ingredient_to_unit_relations;
DROP TABLE IF EXISTS ingrediens;
CREATE TABLE ingrediens (
id serial,
name_of_ingredient varchar(255),
price_per_unit int,
PRIMARY KEY (id)
);
CREATE TABLE ingredient_to_unit_relations (
ingredient_relation_id int GENERATED ALWAYS AS IDENTITY,
PRIMARY KEY (ingredient_relation_id),
constraint Fk_ingredient_id
FOREIGN KEY (id)
REFERENCES ingrediens (id)
);
You need to define the column in order to declare it as a foreign key:
CREATE TABLE ingredient_to_unit_relations (
ingredient_relation_id int GENERATED ALWAYS AS IDENTITY,
ingredient_id int,
PRIMARY KEY (ingredient_relation_id),
constraint Fk_ingredient_id FOREIGN KEY (ingredient_id) REFERENCES ingrediens (id)
);
I might recommend some somewhat different naming conventions (I changed the name id in the table above):
CREATE TABLE ingredients (
ingredient_id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name varchar(255),
price_per_unit int
);
CREATE TABLE ingredient_to_unit_relations (
ingredient_relation_id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
ingredient_id int,
CONSTRAINT Fk_ingredient_id FOREIGN KEY (ingredient_id) REFERENCES ingredients (ingredient_id)
);
Notes:
I am a fan of naming primary keys after the table they are in. That way, foreign keys and primary keys usually have the same name (and you can use using if you choose).
Avoid SERIAL. GENERATED ALWAYS AS IDENTITY is now recommended.
You can inline primary key constraints (as well as other constraints).
There is not generally a need to repeat the table name in a column (other than the primary key). So, name instead of name_of_ingredient.
Using int for a monetary column is suspicious. It doesn't allow smaller units. That might work for some currencies but in general I would expect a numeric/decimal type.

Foreign key referencing primary key of multiple values

Im using ms sql server. I get this msg when I reference a primary key that is a composite key of 3 values in the foreign key.
"number of referencing columns in foreign key differs from the number of reference columns". The problem lies in second last line of code in member booking. Any ideas? Thanks in advance.
CREATE TABLE room
(
Block CHAR (1),
Lvl INT,
rNum INT,
RmType VARCHAR (15),
Condition VARCHAR (15),
CONSTRAINT room_PK PRIMARY KEY (Block, Lvl, rNum),
)
CREATE TABLE booking
(
BookingID INT,
BStartDate DATE,
BEndDate DATE,
Fee DECIMAL (8,2) NOT NULL CHECK (fee >= 0),
Memberbooking INT NOT NULL,
MemberID INT NOT NULL,
CONSTRAINT booking_pk PRIMARY KEY (BookingID),
CONSTRAINT FK_Booking FOREIGN KEY (Memberbooking) references room (Block, Lvl, rNum),
CONSTRAINT FK_MemberID FOREIGN KEY (MemberID) references member (ID)
)
You are getting an error because you are trying to map 1 column (FOREIGN KEY (Memberbooking)) with 3 columns room (Block, Lvl, rNum)
it's possible to create a foreign key relationship to a compound (more
than one column) primary key, make sure to specify the same number of columns in your FOREIGN KEY
You define this constraint in the table booking:
CONSTRAINT FK_Booking FOREIGN KEY (Memberbooking) references room (Block, Lvl, rNum)
meaning that you want the column Memberbooking to reference 3 columns (!!) in the table room.
Each column from a table can reference one column from another table, not multiple ones.
You can define the same column to reference more than 1 columns in another table, but with different constraints, and always 1 to 1.
Read more here: Create Foreign Key Relationships
Since I see from the comments you are intent to implement this type of check, I would propose a check constraint:
CONSTRAINT CK_MemberID CHECK (EXISTS(SELECT 1 FROM room where Memberbooking=room.Block+convert(nchar,room.Lvl)+convert(nchar,room.rNum)))
However, this design is not very good. The lack of seperators in the Membermooking field might cause collisions.
Eg, consider you have a Memberbooking: 'A1101'
Is that Block A, Lvl 11, rNum 01? Or is it Block A, Lvl 1, rNum 101?
On table "room", you currently have a compound natural key. This is a valid design decision. The alternative would be to add a single column artificial id, such as an int Identity. That would lead to two keys on the same table (one of them Primary Key, the other one Unique constraint).
In a foreign key constraint, you can reference any Unique constraint or Primary Key. If you want to keep the "room" table the way it is, then you need to mirror those key fields in the referencing table. So that would mean your "booking" table would need a Block char(1), Lvl int and rNum int column.
That is why an artificial key (on room) can be useful, because then your foreign key constraint (on booking) can be single column and reference that Unique constaint.

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 table creation error : There are no primary or candidate keys in the referenced

A very basic script is driving me crazy. It says it cant find a referenced key. Not idea what it's all about. I'm am using SQL SERVER 2014 and this script is for the creation of my database tables. I'm trying to make the id_TABLE_1 in the table TABLE_2 reference the id of the table TABLE_1.
CREATE TABLE TABLE_1
(
id int identity,
email varchar(50) not null,
constraint PK_TABLE_1 primary key (id,email)
)
GO
CREATE TABLE TABLE_2
(
id int identity,
id_TABLE_1 int not null,
constraint PK_TABLE_2 primary key (id),
constraint FK_TABLE_2 foreign key (id_TABLE_1)
references TABLE_1(id) on delete cascade
)
GO
The error is :
Msg 1776, Level 16, State 0, Line 32
There are no primary or candidate keys in the referenced table 'TABLE_1' that match the referencing column list in the foreign key 'FK_TABLE_2'.
Msg 1750, Level 16, State 0, Line 32
Could not create constraint or index. See previous errors.
Can you help me here ?
As per comment, you are trying to reference an index that doesn't exist. The primary key on your TABLE_1 table is a composite key containing two columns: id and email.
For this to compile, you can either alter your primary key to:
CONSTRAINT PK_TABLE_1 PRIMARY KEY (id)
or create a new index on just the id column:
CREATE INDEX IX_TABLE_1_id ON TABLE_1 (id);
It doesn't make sense to have a composite primary key that includes an identity column. The id column is already unique and non-NULL, so it should be the primary key.
If you want the email to be unique as well then remove it from the primary key and declare it as unique.

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.