I'm trying to use check constraint with a row while I only have the private key. I don't know if there is another way to check this kind of stuff, I'm fairly new to SQL, so I'm also open to suggestions.
Here is a minimal example:
I have following tables:
Buildings:
building_id: int GENERATED PRIMARY KEY
Floors:
floor_id: int GENERATED PRIMARY KEY
floor_nr: int
building_id: int FOREIGN KEY REFERENCES Buildings (building_id)
Glasses:
glass_id: int GENERATED PRIMARY KEY
building_id: int FOREIGN KEY REFERENCES Buildings (building_id)
Floors_Glasses:
floor_id: int FOREIGN KEY REFERENCES Floors (floor_id)
glass_id: int FOREIGN KEY REFERENCES Glasses (building_id)
When I want to move a glass to the floor, I need to check if
(SELECT building_id FROM Floors WHERE floor_id = floor.floor_id) == glass.building_id
So I don't have to repeat the query above for each query I write.
Edit:
I end up using constraint triggers as following:
CREATE CONSTRAINT TRIGGER "trigger name"
AFTER UPDATE OF "column name" ON "table name"
FOR EACH ROW EXECUTE PROCEDURE "procedure name"
And raise exceptions as
raise exception 'message' using errcode = 'restrict_violation';
You can always enforce this rule at the app level. However, I'm always distrusful of the apps (since they are full of bugs all the time), so I personally prefer to enforce the rules at the database level, whenever possible.
It's a bit more startup work but saves you a lot of time later on, since it prevents data corruption issues from the start.
You can do:
create table buildings (
building_id int primary key not null
);
create table floors (
building_id int not null references buildings (building_id),
floor_id int not null,
floor_nr int,
primary key (building_id, floor_id)
);
create table glasses (
building_id int not null references buildings (building_id),
glass_id int not null,
glass_price int,
primary key (building_id, glass_id)
);
create table floor_glasses (
building_id int not null,
floor_id int not null,
glass_id int not null,
primary key (building_id, floor_id, glass_id),
foreign key (building_id, floor_id) references floors (building_id, floor_id),
foreign key (building_id, glass_id) references glasses (building_id, glass_id)
);
The key concept is in the last table. There's only one column building_id that is used in two foreign keys references. This reference sharing ensures the floors and glasses referenced in the last table always belong to the same building.
If a glass truly can be on multiple floors at the same time, add building_id to floors_glasses and create compound foreign keys from that table to floors and glasses that include the building_id column. That will guarantee your integrity constraint.
You cannot define a check constraint that references other rows or tables, because it would become invalid as soon as you modify those other objects. For example, restoring a dump might fail.
Related
I've got 3 schemas, Course, Takes, Instructs.
Under course, I have a course_id as primary key which I want to reference the attribute course_id in both takes and instructs. How can I do that?
Currently this is my course schema where I'm only referencing 1 other table
CREATE TABLE Course (
course_id int PRIMARY KEY REFERENCES Takes (course_id),
)
Are you sure you don't have it backwards?
Takes references Course.
Instructs references Course
Would be a more normal arrangement.
You can do ADD CONSTRAINT after table creation if that's truly your model.
As far as I understood, you have the Course table with the primary key course_id. Then, there are tables Takes and Instructs and each of them has to reference the Course table (have course_id as a foreign key). In your query, Course references Takes but it has to be vice versa.
In case none of those tables exist you need to create them as follows:
CREATE TABLE Course (course_id INT PRIMARY KEY);
CREATE TABLE Takes (take_id INT PRIMARY KEY, course_id INT,
FOREIGN KEY (course_id) REFERENCES Course(course_id));
CREATE TABLE Instructs (instruct_id INT PRIMARY KEY, course_id INT,
FOREIGN KEY (course_id) REFERENCES Course(course_id));
In case the tables Takes and Instructs already exist you should modify them with ALTER TABLE:
ALTER TABLE Takes
ADD CONSTRAINT fk_course
FOREIGN KEY (course_id)
REFERENCES Course(course_id);
And the same for the Instructs table.
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.
I was looking for info on foreign keys.... AGAIN! ... and happened to notice on webschools.com they have different examples of the same thing. for the foreign key example they have
CREATE TABLE Orders
(
O_Id int NOT NULL,
OrderNo int NOT NULL,
P_Id int,
PRIMARY KEY (O_Id),
FOREIGN KEY (P_Id) REFERENCES Persons(P_Id)
)
CREATE TABLE Orders
(
O_Id int NOT NULL PRIMARY KEY,
OrderNo int NOT NULL,
P_Id int FOREIGN KEY REFERENCES Persons(P_Id)
)
CREATE TABLE Orders
(
O_Id int NOT NULL,
OrderNo int NOT NULL,
P_Id int,
PRIMARY KEY (O_Id),
CONSTRAINT fk_PerOrders FOREIGN KEY (P_Id)
REFERENCES Persons(P_Id)
)
now..........
what's the difference?...
How do I know which one I'm suppose to use for my database? I have a feeling this will help resolve a lot of the confusion I'm having with SQL...
No difference in effect: They achieve exactly the same thing.
I prefer the in-line version, because it puts the fk definition as close to the column definition as possible.
There's a 3rd way - a separate alter table statement (which I think is the "official" way):
alter table orders
add contraint fk_PerOrders
foreign key p_id references persons(p_id);
You may find some databases don't support one version or the other.
All of them are doing same thing. Use the one which you feel is easy to understand.
All do same (three ways):
In first, you first defined P_Id as int then defined foreign key constraint.
In second, P_Id int FOREIGN KEY REFERENCES Persons(P_Id). P_Id is defecation and foreign key constraint defecation in same line.
In third, a foreign key constraint name is also give fk_PerOrders. that can be useful later when you wants to drop constraint. e.g.
ALTER TABLE Orders
DROP FOREIGN KEY fk_PerOrders
Its always good practice to give name to a constraint.
Is it possible to have a table's foreign key be part of another table's composite primary key?
For example, if I have two tables, one contains information on all active projects of different users and another containing information on what equipment is being used by the projects:
Project Table:
Composite Primary Keys: UserId, ProjectId (neither are unique by themselves)
Equipment Table:
Composite Primary Keys: UserId, ProjectId, EquipmentId (neither are unique by themselves)
Now is it possible to set the ProjectId in the equipment table to be a foreign key from the project table? When I try, I get an error saying that the column in Project Table do not match an existing primary key or unique constraint?
No.
When you create a foreign key, the key that you "point to" in the other table must be a UNIQUE or PRIMARY KEY constraint. You cannot establish a foreign key that points to a column that allow duplicate values. It would be very hard to imagine how the data should "act" if you update one of the duplicate values in the other table (for instance).
To do what you want you must establish a Projects table in which ProjectID is UNIQUE or a PRIMARY KEY and then point foreign keys in both the other tables to that table.
Parenthetically, you use the term "Primary Keys" to describe the columns in each table that make up the primary key. In fact, each table can have one and only one primary key. That key can be composed of one or more columns, but the key itself is still referred to in the singular. This is an important difference when using the primary key to optimize searches.
It do not know if that's a good design practice but for sure it is possible to have a composite foreign key of one table that is the part of the composite primary key of other table.
Say we have a table test1 having a composite primary key (A, B)
Now we can have a table say test2 having primary key (P, Q, R) where in (P,Q) of test2 referencing (A,B) of test2.
I ran the following script in the MySql database and it works just fine.
CREATE TABLE `test1` (
`A` INT NOT NULL,
`B` VARCHAR(2) NOT NULL,
`C` DATETIME NULL,
`D` VARCHAR(45) NULL,
PRIMARY KEY (`A`, `B`));
CREATE TABLE `test2` (
`P` INT NOT NULL,
`Q` VARCHAR(2) NOT NULL,
`R` INT NOT NULL,
`S` DATETIME NULL,
`T` VARCHAR(8) NULL,
PRIMARY KEY (`P`, `Q`, `R`),
INDEX `PQ_idx` (`P`,`Q` ASC),
CONSTRAINT `PQ`
FOREIGN KEY (`P`, `Q`)
REFERENCES `test1` (`A`,`B`)
ON DELETE CASCADE
ON UPDATE CASCADE);
In the above mentioned case, the database is expecting the combination of (A,B) to be unique and it is, being a primary key in test1 table.
But if you try to do something like following, the script would fail. The database would not let you create the test2 table.
CREATE TABLE `test2` (
`P` INT NOT NULL,
`Q` VARCHAR(2) NULL,
`R` DATETIME NULL,
`S` VARCHAR(8) NULL,
`T` VARCHAR(45) NULL,
INDEX `P_idx` (`P` ASC),
INDEX `Q_idx` (`Q` ASC),
CONSTRAINT `P`
FOREIGN KEY (`P`)
REFERENCES `test1` (`A`)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `Q`
FOREIGN KEY (`Q`)
REFERENCES `test1` (`B`)
ON DELETE CASCADE
ON UPDATE CASCADE);
In the above mentioned case database would expect the column A to be unique individually and the same follows for column B. It does not matter if combination of (A,B) is unique.
#Larry Lustig
The foreign key can be part of primary key in the other table.
source: Dependent relationship
Check relationship between tables: Zdarzenie(Event) and TypZdarzenia (type of event)
I came upon this code, marked "error," in an application I'm to update. Running it on a test database gives a cyclical reference error:
The referential relationship will result in a cyclical reference that is not allowed (Constraint name = descriptions_fk_2)
I named the constraints to see which one caused the problem.
CREATE TABLE items (
id INT NOT NULL UNIQUE IDENTITY,
name NCHAR(100) NOT NULL UNIQUE,
PRIMARY KEY (id)
);
CREATE TABLE sources (
id INT NOT NULL UNIQUE IDENTITY,
item_id INT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (item_id)
REFERENCES items(id) ON UPDATE NO ACTION ON DELETE CASCADE
);
CREATE TABLE descriptions (
id INT NOT NULL UNIQUE IDENTITY,
item_id INT NOT NULL,
source_id INT NOT NULL,
PRIMARY KEY (id),
CONSTRAINT descriptions_fk_1 FOREIGN KEY (item_id)
REFERENCES items(id) ON UPDATE NO ACTION ON DELETE CASCADE,
CONSTRAINT descriptions_fk_2 FOREIGN KEY (source_id)
REFERENCES sources(id) ON UPDATE NO ACTION ON DELETE CASCADE
);
Why is this a cyclical reference? The descriptions table is linked to two separate tables, but none of them link back to descriptions.
It's not strictly cyclical - but there are multiple cascade paths. So you could cascade delete a row in items two ways:
1) description -> item
2) description -> source -> item
And, for that reason, it's disallowed.
I believe it's a performance concern, as PostGres will allow cycles like that and will just work it out, but deletes under those circumstances can be quite slow.
For some further reading about why it's disallowed, please see this answer.