Inheritance PostgreSQL - sql

I have 2 tables under PostgreSQL:
a table property that is the mother table (id, created_at ..) and
a habitation table (surface, room, etc...) that inherits property. On the mother table, I have a many-many relationship table. I have added results in the "habitation" table.
When I try to insert "property_table" with habitation IDs, I have a SQL error telling me that the property_id ID does not exist. It exists when I go to see the property or habitation table. I want to insert habitation IDs (so property) in property_tag , should I force insert? Help please
The SQL schemas :
CREATE TABLE "property"
(
id serial NOT NULL,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
address_id int NOT NULL,
permission int NOT NULL DEFAULT 6,
user_id int NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (address_id) REFERENCES "address"(id),
FOREIGN KEY (user_id) REFERENCES "user"(id)
);
CREATE TABLE habitation (
total_surface float,
living_surface float,
ground_surface float,
ground_surface_unity character varying(15) DEFAULT 'm2',
room integer,
bedroom integer,
floor integer,
level integer,
year integer
) INHERITS (property);
CREATE TABLE property_tag
(
tag_id int NOT NULL,
property_id int NOT NULL,
PRIMARY KEY (tag_id, property_id),
FOREIGN KEY (tag_id) REFERENCES "tag"(id) ON DELETE CASCADE,
FOREIGN KEY (property_id) REFERENCES "property"(id) ON DELETE CASCADE
);
CREATE TABLE "tag"
(
id serial NOT NULL,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
name character varying(127) NOT NULL,
user_id int NOT NULL,
color character varying(7) NOT NULL DEFAULT 'A4A4A8',
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES "user"(id) ON DELETE CASCADE
);

When you insert into table "habitation", the row exists physically only in table "habitation", but not in "property".
Your table "property_tag" references to table "property" (which have no rows, cause rows are in table "habitation") and therefore you are getting error during insert.
You have to change your reference in table "property_tag" from "property" to "habitation".

Related

PostgreSQL: How to link 2 tables?

I have a table defined like this:
CREATE TABLE public.journeys (
journey_id uuid NOT NULL UNIQUE DEFAULT uuid_generate_v4(),
name text NOT NULL,
user_id uuid NOT NULL,
date_created timestamptz NOT NULL,
date_deleted timestamptz NULL,
route_id uuid NOT NULL,
CONSTRAINT fk_users
FOREIGN KEY(user_id)
REFERENCES users(user_id)
);
What I want to do now is create a second table that will connect to this table above. Here's its definition:
CREATE TABLE public.routes (
route_id uuid NOT NULL UNIQUE DEFAULT uuid_generate_v4(),
idx smallint NOT NULL,
date timestamptz NULL,
latitude real NOT NULL,
longitude real NOT NULL,
CONSTRAINT route_key
PRIMARY KEY (route_id, idx),
CONSTRAINT fk_journeys
FOREIGN KEY(route_id)
REFERENCES journeys(route_id)
);
The notion is that for every Journey there will be a connected Route that simply consists of a series of Latitude, Longitude points. So for a given route_id in journeys there will be N records in routes. Every record in a given route will share the same route_id but each one will have a unique idx (ie. 0, 1, 2, ...).
This is the error I'm getting when I try creating public.routes:
SQL Error [42830]: ERROR: there is no unique constraint matching given keys for referenced table "journeys"
What am I doing wrong and how do I fix this?
Robert
I read several more threads on the subject and then realized that that journeys.route_id was not being declared as UNIQUE.
So within the public.journeys declaration, this fixed the problem:
route_id uuid NOT NULL UNIQUE,

SQL - deleting rows from other tables with on cascade not working

I have 4 related tables: order_info, master_bill, master_bill_order_leg and order_leg.
MasterBill and OrderLeg have many to many relationship.
This is the quick documentation from IntelliJ for the DB tables.
Table master_bill:
create table master_bill
(
id bigint not null
primary key,
mb_no bigint not null,
created_by text not null,
updated_by text not null,
created_at timestamp with time zone default now() not null,
updated_at timestamp with time zone default now() not null
);
Table order_info:
create table order_info
(
order_id bigint not null
primary key
references public.order_t
on delete cascade,
mb_id bigint not null
references master_air_waybill
on delete cascade,
created_by text not null,
updated_by text not null,
created_at timestamp with time zone default now() not null,
updated_at timestamp with time zone default now() not null
);
Table master_bill_order_leg:
create table master_bill_order_leg
(
mb_id bigint
references master_bill
on delete cascade,
order_leg_id bigint
references order_leg
on delete cascade,
constraint master_bill_order_mb_id_order_leg_id_key
unique (mb_id, order_leg_id)
);
Table order_leg:
create table order_leg
(
id bigserial
primary key,
created_by text not null,
updated_by text not null,
created_at timestamp with time zone default now() not null,
updated_at timestamp with time zone default now() not null,
constraint order_leg_unique_c
unique (flight_id, flight_date, departure_iata, arrival_iata)
);
I have set the foreign keys and they look like this:
Table master_bill_order_leg
master_bill_order_leg_mb_id_fkey (mb_id) -> master_bill(id)
master_bill_order_leg_order_leg_id_fkey (order_leg_id) -> order_leg(id)
Table order_info
order_info_mb_id_fkey (mb_id) -> master_bill(id) ON DELETE CASCADE
order_info_order_id_fkey (order_id) -> order_t(id) ON DELETE CASCADE
I thought that if order from order_t table is deleted that all relevant rows from other tables would be deleted too, but that is not the case, only order_info row is deleted on cascade. So, I have tried with deleting a row from master_bill table:
DELETE
FROM master_bill
WHERE id = :mbId
But, then I get an error:
org.postgresql.util.PSQLException: ERROR: update or delete on table
"master_bill" violates foreign key constraint
"master_bill_order_leg_mb_id_fkey" on table
"master_bill_order_leg" Detail: Key (id)=(1076) is
still referenced from table "master_bill_order_leg".
I thought that this foreign key would delete on cascade from master_bill_order_leg table if I delete a row from master_bill, since master_bill is a parent table.
What am I doing wrong here?
You can use both foreign key and trigger to achieve this. (Result here)
create table master_bill
(
id bigint not null primary key,
mb_no bigint not null,
created_by text not null,
updated_by text not null,
created_at timestamp with time zone default now() not null,
updated_at timestamp with time zone default now() not null
);
create table order_info
(
order_id bigint not null primary key,
mb_id bigint not null references master_bill(id) on delete cascade,
created_by text not null,
updated_by text not null,
created_at timestamp with time zone default now() not null,
updated_at timestamp with time zone default now() not null
);
create table master_bill_order_leg
(
mb_id bigint references master_bill(id) on delete cascade,
order_leg_id bigint,
constraint master_bill_order_mb_id_order_leg_id_key unique (mb_id, order_leg_id)
);
create table order_leg
(
id bigint primary key,
created_by text not null,
updated_by text not null,
created_at timestamp with time zone default now() not null,
updated_at timestamp with time zone default now() not null
);
CREATE OR REPLACE FUNCTION public.f_delete_order_leg()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
begin
delete from order_leg where id in (select order_leg_id from old_table);
return null;
end;
$function$
;
create trigger t_delete_order_leg
after delete
on master_bill_order_leg
referencing old table as old_table
for each statement
execute function f_delete_order_leg();
The way a CASCADE DELETE works is when you delete a record in the parent table, the related records in the child table are deleted
When you are running
DELETE
FROM order_info
WHERE order_id = :id
this is a child table (its FK references a PK in a parent table) it doesn't have any foreign keys in other tables that reference it
A simple example of how cascade deletes works is a two table database of departments and employees - one department can have many employees and this is enforced by an FK / PK relationship:
CREATE TABLE Department
(
DeptId INT PRIMARY KEY,
DeptName VARCHAR(10)
);
CREATE TABLE Employee
(
EmployeeID INT ,
EmployeeName VARCHAR(10),
DepartmentID INT,
CONSTRAINT DepartmentID_FK foreign key (DepartmentID) references Department(DeptId) ON DELETE CASCADE
);
INSERT INTO Department VALUES (1,'IT'),(2,'HR');
INSERT INTO Employee VALUES (1,'John',2),(2,'Kim',2),(3,'Sam',1);
At this point, if I run
SELECT * FROM Employee
I get 3 records.
If I delete a department from the parent table:
DELETE FROM Department WHERE DeptID = 2
and I run the select again, I now have 1 record (Sam) as the cascade delete has deleted those employees in department ID 2 (john and Kim)

PostgreSQL cyclic foreign keys to multiple tables

I have 3 tables.
chat_room
create table chat_room
(
id uuid default uuid_generate_v4() not null
constraint chat_room_pk
primary key
constraint fk__chat_room__group_chat_room
references group_chat_room
on update cascade on delete cascade
constraint fk__chat_room__private_chat_room
references private_chat_room
on update cascade on delete cascade,
name varchar(255) not null,
description varchar(255),
profile_pic varchar(128),
created_at timestamp with time zone default now() not null,
updated_at timestamp with time zone
);
group_chat_room
create table group_chat_room
(
id uuid not null
constraint group_chat_room_pk
primary key
constraint fk__group_chat_room___chat_room
references chat_room
on update cascade on delete cascade,
pus_code char(7) not null
constraint fk__group_chat_room__puskesmas
references puskesmas
on update cascade on delete cascade
);
create unique index group_chat_room_pus_code_uindex
on group_chat_room (pus_code);
private_chat_room
create table private_chat_room
(
id uuid not null
constraint private_chat_room_pk
primary key
constraint fk__private_chat_room__chat_room
references chat_room
on update cascade on delete cascade
);
As you can see chat_room has foreign key constraints that refer to group_chat_room and private_chat_room. Also both group_chat_room and private_chat_room have FK constraints that refer to chat_room.
When I want to INSERT a row into group_chat_room I would use this
with chat_room as (
insert into chat_room (id, name) values ('Some ID', 'Some Name')
)
insert into group_chat_room(id, pus_code) values ('Some ID', 'Some Code');
However because of those constraints this would produce an error
[23503] ERROR: insert or update on table "chat_room" violates foreign key constraint "fk__chat_room__private_chat_room" Detail: Key (id)=(cef8c655-d46a-4f63-bdc8-77113b1b74b4) is not present in table "private_chat_room".
How do I only insert to group_chat_room without having to insert it to private_chat_room?
The main problem here is creating multiple required bidirectional foreign keys. You can probably work around it, eventually. But it makes the data model more complicated and the code much more so. And it is completely unnecessary. Everything you have can be accomplished with just 1 table. If group_chat_room and private_chat_room are independently required then create a view for each. Further, as simple views, they are fully update-able.
You accomplish this by moving the column 'pus_code' to chat_room and adding 2 boolean values to indicate if this is a private or group room or both. Yes, strange as it sounds you can get a private_group_chat_room. (Note: there is nothing in your design preventing it and the error you are getting is because it is required). If you do want that then create a check constraint requiring at least 1 of the boolean columns be false.
create table chat_room
(
id integer generated always as identity
constraint chat_room_pk
primary key,
name varchar(255) not null,
description varchar(255),
profile_pic varchar(128),
is_private boolean not null default false,
is_group boolean not null default false,
pus_code varchar(7)
constraint fk__group_chat_room__puskesmas
references puskesmas
on update cascade on delete cascade,
created_at timestamp with time zone default now() not null,
updated_at timestamp with time zone,
constraint not_group_of_pus_code_check
check ( (not is_group and pus_code is null)
or (is_group and pus_code is not null)
)
);
-- create unique partial index
create unique index group_chat_room_pus_code_uindex on chat_room(pus_code)
where is_group;
-- group_chat_room
create view group_chat_room
( id
, name
, description
, profile_pic
, is_private
, pus_code
, created_at
, updated_at
) as
select id
, name
, description
, profile_pic
, is_private
, pus_code
, created_at
, updated_at
from chat_room
where is_group;
-- private_chat_room
create view private_chat_room
( id
, name
, description
, profile_pic
, is_group
, pus_code
, created_at
, updated_at
) as
select id
, name
, description
, profile_pic
, is_group
, pus_code
, created_at
, updated_at
from chat_room
where is_private;
See fiddle for full example and a few tests. Note: fiddle has an issue with generate_uuid_v4() (did not exist) so for demo I changed to identity. It will fine in an operational environment.

using foreign key value directly in INSERT INTO statement

is it possible to use the value of the foreign key directly with an INSERT INTO statement? I am using Postgresql and the tables are consttructed as follows:
CREATE TABLE public.sensors
(
name character varying(100) COLLATE pg_catalog."default",
description text COLLATE pg_catalog."default",
id integer NOT NULL DEFAULT nextval('sensors_id_seq'::regclass),
CONSTRAINT sensors_pkey PRIMARY KEY (id)
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public.sensors
OWNER to postgres;
Now I also have another table, defined as:
CREATE TABLE public.testmap
(
sensor_id integer NOT NULL,
"timestamp" timestamp with time zone NOT NULL,
value "char" NOT NULL,
CONSTRAINT ragmap_sensor_id_fkey FOREIGN KEY (sensor_id)
REFERENCES public.sensors (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public.ragmap
OWNER to postgres;
Now, I try to insert a record directly into the testmap table as:
INSERT INTO testmap (sensor_id, timestamp, value) VALUES (1, NOW(), 'r')
I have a record inserted into the sensors table where the id is 1. However, when I try the INSERT INTO operation, I get:
DETAIL: Key (sensor_id)=(1) is not present in table "sensors".
Is there a way to use the INSERT INTO with the foreignh key directly without having to resort to another Select for the relevant row selection in the sensors table?
Your code doesn't even work. The column id is specified more than once for sensors.
I don't recommend having a character column as a primary key. If you do so, you should be explicit about your types:
INSERT INTO testmap (sensor_id, timestamp, value)
VALUES ('1', NOW(), 'r');
The problem is that your foreign key reference is a number but the primary key is an integer.
Instead, define the primary key to be a number:
CREATE TABLE public.sensors (
id serial primary key,
name character varying(100) COLLATE pg_catalog."default",
description text COLLATE pg_catalog."default",
id integer NOT NULL DEFAULT nextval('sensors_id_seq'::regclass),
CONSTRAINT sensors_pkey PRIMARY KEY (id)
)

Foreign key Constraint on delete cascade does not work postgres

When I run DELETE FROM users WHERE id='some_id' the record on beta_keys table does not get deleted.
beta_keys table:
CREATE TABLE beta_keys (
id serial PRIMARY KEY,
key VARCHAR(60) UNIQUE NOT NULL,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP
);
users table:
CREATE TABLE users (
id serial PRIMARY KEY,
email VARCHAR (256) UNIQUE NOT NULL,
password VARCHAR (60) NOT NULL,
beta_key_id INTEGER,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP,
CONSTRAINT users_beta_key_id_fkey FOREIGN KEY (beta_key_id)
REFERENCES beta_keys (id) MATCH SIMPLE
ON DELETE CASCADE
);
users references beta_keys. delete cascade works by deleting referencing rows (users) when the referenced row (beta_keys) is deleted.
sqlfiddle: http://sqlfiddle.com/#!17/a7495/1