How to add a foreign key for table B by referring of table A and foreign key for table A by referring table B in PostgreSQL? - postgresql

I need to add a foreign keys for two tables each other. Can this be done ?
As an example:
CREATE SCHEMA IF NOT EXISTS schema1;
CREATE TABLE schema1.tableA
(
id serial NOT NULL,
tableB_id integer,
PRIMARY KEY (id),
FOREIGN KEY (tableB_id) REFERENCES schema1.tableB (id)
);
CREATE TABLE schema1.tableB
(
id serial NOT NULL,
tableA_id integer,
PRIMARY KEY (id),
FOREIGN KEY (tableA_id) REFERENCES schema1.tableA(id)
);
Above query causes an error !
ERROR: relation "schema1.tableb" does not exist SQL state: 42P01
Can this be done or is there any better solution?
I'am using PostgreSQL version 10.5 and pgAdmin 3.6

Add the foreign keys after creating both tables:
CREATE SCHEMA IF NOT EXISTS schema1;
CREATE TABLE schema1.tableA
(
id serial NOT NULL,
tableB_id integer,
PRIMARY KEY (id)
);
CREATE TABLE schema1.tableB
(
id serial NOT NULL,
tableA_id integer,
PRIMARY KEY (id)
);
ALTER TABLE schema1.tablea
add FOREIGN KEY (tableB_id) REFERENCES schema1.tableB (id);
ALTER TABLE schema1.tableb
add foreign key (tableA_id) REFERENCES schema1.tableA(id);

Related

DB2 referential constraint cannot created

I can not add a referential constraint, both tables has the two columns id and version as primary key. I will only check the integrity that the row is existing without checking version.
CREATE TABLE TABLEE
(ID INTEGER NOT NULL,
VERSION INTEGER NOT NULL,
PRIMARY KEY (ID , VERSION);
CREATE TABLE CHAIR
(ID INTEGER NOT NULL,
VERSION INTEGER NOT NULL,
ID_TABLEE INTEGER,
PRIMARY KEY (ID , VERSION);
ALTER Chair
ADD constraint MYC FOREIGN KEY (ID)
REFERENCES TABLEE (ID)
ON DELETE RESTRICT
Got this error
[Code: -573, SQL State: 42890] A column list specified in the references clause of constraint "MYC " does not identify a unique constraint of the parent table or nickname "TABLEE".. SQLCODE=-573, SQLSTATE=42890, DRIVER=4.28.11
The problem here is that Tablee its primary key consists of two columns id and version. But the integrity check should only be made on the referenced id, not version.
To establish a foreign key on a table the referenced column needs to:
Be a primary key on the other table.
...or at least act as one.
Since you already have a primary key on the referenced table, you can use the second approach and add a UNIQUE and NOT NULL constraints on ID.
For example:
CREATE TABLE TABLEE (
ID INTEGER NOT NULL,
VERSION INTEGER NOT NULL,
PRIMARY KEY (ID , VERSION),
constraint uq1 unique (id) -- added UNIQUE constraint on ID
);
CREATE TABLE CHAIR (
ID INTEGER NOT NULL,
VERSION INTEGER NOT NULL,
ID_TABLEE INTEGER,
PRIMARY KEY (ID , VERSION)
);
ALTER table Chair
ADD constraint MYC FOREIGN KEY (ID)
REFERENCES TABLEE (ID)
ON DELETE RESTRICT;
See running example at db<>fiddle.
Note: If you want ID to have repeated values over the table, then ID is not a key, and cannot be referenced as one.

Does postgresql require unique constraint names when defining FOREIGN KEYS

Here is my schema for database tables:
CREATE TABLE users (
user_id INTEGER NOT NULL,
device_id INTEGER,
user_points INTEGER,
cookie VARCHAR,
PRIMARY KEY (user_id)
);
CREATE TABLE admins (
admin_id INTEGER NOT NULL,
username VARCHAR,
password VARCHAR
);
CREATE TABLE admin_adventure (
adventure_id INTEGER NOT NULL,
admin_id INTEGER,
PRIMARY KEY (adventure_id)
);
CREATE TABLE adventures (
adventure_id INTEGER NOT NULL,
prize_id INTEGER,
novella_id INTEGER,
PRIMARY KEY (adventure_id)
);
Here I'm trying to define FOREIGN KEYS:
ALTER TABLE admin_adventure ADD FOREIGN KEY ( admin_id ) REFERENCES admins ( admin_id );
ALTER TABLE admin_adventure ADD FOREIGN KEY ( adventure_id ) REFERENCES adventures ( adventure_id );
And here is the error I get when trying to migrate with Flyway:
ERROR: there is no unique constraint matching given keys for
referenced table "admins"
Can someone explain what I'm doing wrong and why I get this error?
The error message is complaining that you are trying to link a foreign key to a column in another table which is not unique (e.g. a primary key). Try making the admin_id column in the admins table a primary key:
CREATE TABLE admins (
admin_id INTEGER NOT NULL,
username VARCHAR,
password VARCHAR,
PRIMARY KEY (admin_id)
);
Like the documentation says:
A foreign key must reference columns that either are a primary key or form a unique constraint.
So you must either
ALTER TABLE admins ADD PRIMARY KEY (admin_id);
or
ALTER TABLE admins ADD UNIQUE (admin_id);

Resolving ON DELETE CASCADE in many-to-many relation

See: SQLFiddle
I am having a many-to-many relationship as such:
CREATE TABLE IF NOT EXISTS store (
id BIGSERIAL PRIMARY KEY
);
CREATE TABLE IF NOT EXISTS collection (
id BIGSERIAL PRIMARY KEY,
store_id bigint NOT NULL,
FOREIGN KEY (store_id) REFERENCES store (id)
ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS item (
id BIGSERIAL PRIMARY KEY,
store_id bigint NOT NULL,
FOREIGN KEY (store_id) REFERENCES store (id)
ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS collection_item (
id BIGSERIAL PRIMARY KEY,
collection_id bigint NOT NULL,
item_id bigint,
UNIQUE (collection_id, item_id),
FOREIGN KEY (collection_id) REFERENCES collection (id)
ON DELETE CASCADE,
FOREIGN KEY (item_id) REFERENCES item (id)
ON DELETE SET NULL
);
INSERT INTO store (id) VALUES (1);
INSERT INTO item (id, store_id) VALUES (1, 1);
INSERT INTO collection (id, store_id) VALUES (1, 1);
INSERT INTO collection_item (id, collection_id, item_id) VALUES (DEFAULT, 1, 1);
My problem is that deleting a store
DELETE FROM store WHERE store.id = 1;
will give the following error:
ERROR: update or delete on table "store" violates foreign key constraint
"collection_store_id_fkey" on table "collection"
Detail: Key (id)=(1) is still referenced from table "collection".
I understand the problem but I don't know how I can resolve this issue.
If an item gets deleted, the relation in collection_item should not be removed but the item_id should be set to NULL. On the other hand, if a collection gets deleted, all related collection_item records should be removed as well.
How can DELETE CASCADE work in such a setup or do I have to model my tables differently if I need this kind of behavior?
You can just add ON DELETE CASCADE where you have ON UPDATE CASCADE
CREATE TABLE IF NOT EXISTS collection (
id BIGSERIAL PRIMARY KEY,
store_id bigint NOT NULL,
FOREIGN KEY (store_id) REFERENCES store (id)
ON UPDATE CASCADE
ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS item (
id BIGSERIAL PRIMARY KEY,
store_id bigint NOT NULL,
FOREIGN KEY (store_id) REFERENCES store (id)
ON UPDATE CASCADE
ON DELETE CASCADE
);
SQLFiddle
To resolve this issue you can add ON DELETE behavior to the store_id column of the collection table (and that of the item table). Basically you can just change the ON UPDATE to ON DELETE in both of these table definitions, since I doubt you'll be updating the id column for existing rows in the store table. You also mention the ON DELETE behavior for the item_id column of collection_item, if you want the column value to become NULL when an item is deleted, you can use ON DELETE SET NULL.
CREATE TABLE IF NOT EXISTS store (
id BIGSERIAL PRIMARY KEY
);
CREATE TABLE IF NOT EXISTS collection (
id BIGSERIAL PRIMARY KEY,
store_id bigint NOT NULL,
FOREIGN KEY (store_id) REFERENCES store (id)
ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS item (
id BIGSERIAL PRIMARY KEY,
store_id bigint NOT NULL,
FOREIGN KEY (store_id) REFERENCES store (id)
ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS collection_item (
id BIGSERIAL PRIMARY KEY,
collection_id bigint NOT NULL,
item_id bigint NOT NULL,
UNIQUE (collection_id, item_id),
FOREIGN KEY (collection_id) REFERENCES collection (id)
ON DELETE CASCADE,
FOREIGN KEY (item_id) REFERENCES item (id)
ON DELETE SET NULL
);
On this case, you have to delete table refrences before to delete stores id.
Or to do the modifications above.
DELETE FROM item where store_id= 1;
DELETE FROM collection where store_id = 1;
DELETE FROM store where id = 1;

Find cause of error "constraint xxxx is not a foreign key constraint" in Postgresql

I have defined these tables:
CREATE TABLE "public".category (id BIGSERIAL NOT NULL, name varchar(255) NOT NULL, PRIMARY KEY (id));
CREATE UNIQUE INDEX category_name ON "public".category (name);
CREATE TABLE "public".clusters (id BIGSERIAL NOT NULL, name varchar(255) NOT NULL, PRIMARY KEY (id));
CREATE INDEX clusters_name ON "public".clusters (name);
CREATE TABLE "public".keywords (id BIGSERIAL NOT NULL, text varchar(255) NOT NULL, category_id int8 NOT NULL, top_results int4, cluster_id int8, month_requests int4, click_cost float8, PRIMARY KEY (id));
CREATE INDEX keywords_text ON "public".keywords (text);
ALTER TABLE "public".keywords ADD CONSTRAINT FKkeywords488682 FOREIGN KEY (cluster_id) REFERENCES "public".clusters (id);
ALTER TABLE "public".keywords ADD CONSTRAINT FKkeywords446526 FOREIGN KEY (category_id) REFERENCES "public".category (id) ON UPDATE CASCADE ON DELETE CASCADE;
added one record to category table:
INSERT INTO "public".category(id, name) VALUES (1, 'Test');
And now when I try to add record to keyword table
insert into "public"."keywords" ( "category_id", "text") values ( 1, 'testkey')
I got error:
ERROR: constraint 16959 is not a foreign key constraint
When I do
select * FROM pg_constraint;
I can't see constraint with this id. I can't understand what is the cause of this problem.

Foreign keys in Postgres

i´ve got a problem with foreign keys, it´s an strange problem.
First table:
CREATE TABLE adjunto
(
id serial NOT NULL,
codigo text,
descripcion text,
usuario integer,
file integer,
nombre text,
propiedades hstore,
CONSTRAINT adjunto_pkey PRIMARY KEY (id ),
CONSTRAINT adjunto_file_fkey FOREIGN KEY (file)
REFERENCES file (file_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE CASCADE
) WITH (
OIDS=FALSE
);
Second table:
CREATE TABLE adjunto_coleccion_privada
(
id serial NOT NULL,
adjunto integer,
coleccion integer,
CONSTRAINT adjunto_coleccion_privada_pkey PRIMARY KEY (id ),
CONSTRAINT adjunto_coleccion_privada_adjunto_fkey FOREIGN KEY (adjunto)
REFERENCES adjunto (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE CASCADE,
CONSTRAINT adjunto_coleccion_privada_coleccion_fkey FOREIGN KEY (coleccion)
REFERENCES coleccion (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE CASCADE
)
WITH (
OIDS=FALSE
);
Command:
INSERT INTO adjunto_coleccion_privada (adjunto, coleccion)
VALUES (600, 2) RETURNING id
Values 600 and 2 exist in both tables, adjunto and colecion.
Detailed error:
Mensaje: ERROR: insert or update on table "adjunto_coleccion_privada"
violates foreign key
constraint "adjunto_coleccion_privada_adjunto_fkey"
Detail: Key (adjunto)=(600) is not present in table "adjunto".
I tested your code (I dropped the adjunto_coleccion_privada_coleccion_fkey constraint since referred table does not exist in your pasted code).
I see no problem at all.
Are you really sure that there is a record with id = 600 in the adjunto table?