Postgresql, references to unique constraint - sql

I'm running PostgreSQL 9.4 and have the following table:
CREATE TABLE user_cars (
user_id SERIAL REFERENCES users (id) ON DELETE CASCADE,
car CHARACTER VARYING(255) NOT NULL,
CONSTRAINT test UNIQUE (user_id, car)
);
The table allows a user to have multiple cars, but only use the car name once. But other users may have the same car name.
I would like to have another table with references to the unique constraint test, and have tried stuff like:
CREATE TABLE mappings (
other_id CHARACTER(9) REFERENCES other (id) ON DELETE CASCADE,
user_cars REFERENCES user_cards (test) ON DELETE CASCADE
);
But that fails "obviously". I would like to make sure that other_id only have a single references to a user_car entry.
So to explain, how can I in table mappings have a references to test from table user_cars.
This is the thing that fails currently:
user_cars REFERENCES user_cards (test) ON DELETE CASCADE

Don't use composite foreign key references, if you can avoid it. Just add a unique id to the table:
CREATE TABLE user_cars (
user_car_id serial primary key,
user_id int REFERENCES users (id) ON DELETE CASCADE,
car CHARACTER VARYING(255) NOT NULL,
CONSTRAINT test UNIQUE (user_id, car)
);
Then mappings is simply:
CREATE TABLE mappings (
mapping_id serial primary key,
user_car_id int references user_cars(user_car_id) on delete cascade,
other_id CHARACTER(9) REFERENCES other (id) ON DELETE CASCADE,
);

If car should be unique, add UNIQUE constrain only on car column.
If user should be unique, add UNIQUE constrain only on user column.
If you add UNIQUE constrain on combination, then there will be duplicate values in the table.
UPDATE:
You can add multiple constraints on single column. With Foreign key add UNIQUE constraint as well on user_cars column in mapping table.

Related

How to add delete cascade on staging table

Here how I created tables:
CREATE TABLE TABLE_A(
id uuid NOT NULL, UNIQUE
name text
);
CREATE TABLE TABLE_B(
id uuid NOT NULL, UNIQUE
name text
);
-- custom realization of many-to-many association
CREATE TABLE TABLE_A_B(
id uuid NOT NULL, UNIQUE
a_id uuid REFERENCES TABLE_A(id) ON UPDATE CASCADE,
B_id uuid REFERENCES TABLE_B(id) ON UPDATE CASCADE
);
I've already created tables and now can't update it by adding ON DELETE CASCADE.
And I need now to add ON DELETE CASCADE to staging table TABLE_A_B. How to do it ?(
You use ON DELETE CASCADE:
CREATE TABLE TABLE_A_B(
id uuid NOT NULL UNIQUE,
a_id uuid REFERENCES TABLE_A(id) ON UPDATE CASCADE ON DELETE CASCADE,
B_id uuid REFERENCES TABLE_B(id) ON UPDATE CASCADE ON DELETE CASCADE
);
Here is a db<>fiddle that fixed some typos in your code.
In particular, the foreign key reference should be to a primary key. Although allowed to a unique key, the purpose of primary keys is really to identify individual rows -- and one main use is for foreign key references.
EDIT:
If the constraints already exist, then do the following.
First, get their names:
select *
from information_schema.table_constraints
where constraint_type = 'FOREIGN KEY' and table_name = 'table_a_b';
Note: You can assign names to skip this step.
Then drop the existing foreign key constraint:
alter table table_a_b
drop constraint table_a_b_a_id_fkey;
Finally, add a new one:
alter table table_a_b
add constraint fk_table_a_b_a
foreign key (a_id) references table_a(id)
on update cascade
on delete cascade;

PostgreSQL assigns foreign key automatically on the referencing side

So I've got Table ActorInMovies, which has 3 foreign keys.
CREATE TABLE ActorInMovie(
ID_ROLE bigserial REFERENCES Role(ID_ROLE) ON DELETE CASCADE,
ID_ACTOR bigserial REFERENCES Actor(ID_Actor) ON DELETE CASCADE,
ID_MOVIE bigserial REFERENCES Movie(ID_Movie) ON DELETE CASCADE,
CONSTRAINT ActorInMovie_pk PRIMARY KEY (ID_ROLE));
I assumed that when I try to insert something like:
INSERT INTO ActorInMovie (ID_ROLE, ID_ACTOR) values (1,1);
that it would result in an error as ID_MOVIE was not specified (null I supposed).. but it automatically starts assigning indexes staring from 1.
What am I doing wrong? As written here, I thought that "PostgreSQL automatically creates indexes on primary keys and unique constraints, but not on the referencing side of foreign key relationships."
I have a very hard time imagining a use case where a serial(or bigserial) column references another column. It's usually the other way round: the serial column should go on the other end of the foreign key constraint.
I have an equally hard time imagining a design where a movie_id needs to be bigint instead of just int. There aren't nearly enough movies on this planet.
Also, there is a good chance, a column called movie_id in a table called actor_in_movie should be defined as NOT NULL.
In short: I doubt your design flies at all. Maybe something like:
CREATE TABLE actor (actor_id serial PRIMARY KEY, actor text, ...);
CREATE TABLE movie (movie_id serial PRIMARY KEY, movie text, ...);
CREATE TABLE actor_in_movie(
role_id serial PRIMARY KEY
,actor_id int NOT NULL REFERENCES actor(actor_id) ON DELETE CASCADE
,movie_id int NOT NULL REFERENCES movie(movie_id) ON DELETE CASCADE
);
A NOT NULL constraint is redundant, while the column is included in the primary key.
You probably want indices on actor_id and on movie_id in actor_in_movie.
More details:
How to implement a many-to-many relationship in PostgreSQL?
This is simply bigserial working exactly as advertised. It has nothing to do with the foreign key constraint, or with an index.

Why is this a cyclical foreign key constraint?

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.

How to insert a record in many to many relationship tables?

For exmple i have two tables
A
create table teachers(
id number(4) primary key,
name varchar(20)
);
B
create table students(
id number(4) primary key,
name varchar(20)
);
and a third table
AB
create table Teacher_Student(
T_Id number(4),
S_Id number(4)
);
and their relationship
alter table teacher_student
add constraint s_t_pk Primary key(T_Id, S_Id);
Is this relationship is created correctly? and what would be the insertion query if i want to add a new student or a teacher.
Suggestion: also add referential integrity constraints:
alter table teacher_student
add constraint s_t_fk_t foreign key (T_Id)
references teachers (id)
on delete cascade
on update cascade;
alter table teacher_student
add constraint s_t_fk_s foreign key (S_Id)
references students (id)
on delete cascade
on update cascade;
Usual manouever for this would require primary keys for student and teacher tables, and then foreign keys for T_Id and S_id to Teachers and Students from Teacher_Student.
When you've done that, inserting to student and teacher, would only check uniqueness of their keys, i.e , you can't have two student's with an id of 1.
Inserting to Teacher_Student would check uniqueness of the relationship, and that the inserted ids exist in their respective tables.
PS abbreviating database object names is a very objectionable habit.

Enforcing unique rows in a many-to-many junction table

I have a junction table for a many-to-many relationship that just links two foreign keys together. However I've found that this will not prevent duplicate identical row entries. What's the proper way of handling that? I thought adding PRIMARY KEY to the two foreign keys would do it, but it seems like I'm not understanding that correctly.
CREATE TABLE ab_link (
a_id bigint REFERENCES a(a_id) PRIMARY KEY,
b_id bigint REFERENCES b(b_id) PRIMARY KEY
);
I found on another question this example:
CREATE TABLE bill_product (
bill_id int REFERENCES bill (bill_id) ON UPDATE CASCADE ON DELETE CASCADE
, product_id int REFERENCES product (product_id) ON UPDATE CASCADE
, amount numeric NOT NULL DEFAULT 1
, CONSTRAINT bill_product_pkey PRIMARY KEY (bill_id, product_id) -- explicit pk
);
Is that constraint the best way of enforcing uniqueness? I would think there would be some way of doing it without having a third row.
For a compound primary key, you need a separate declaration:
CREATE TABLE ab_link (
a_id bigint REFERENCES a(a_id),
b_id bigint REFERENCES b(b_id),
PRIMARY KEY (a_id, b_id)
);