Postgres: insert multiple rows on conflict update not working - postgresql

I am trying to insert multiple rows into a table, and, in case of conflict, simply update them. What am I doing wrong?
insert into segments(id, departure_hour)
values
(1153, 2),
(1156, 4),
(1154, 2)
on conflict do update set
departure_hour = c.departure_hour
from (values
(1153, 2),
(1156, 4),
(1154, 2))
as c(id, departure_hour)
where c.id = segments.id
As requested, here is my table definition:
CREATE TABLE segments (
id SERIAL PRIMARY KEY,
route_id integer NOT NULL REFERENCES routes(id),
origin_id integer NOT NULL REFERENCES stops(id),
destination_id integer NOT NULL REFERENCES stops(id),
price integer DEFAULT 0,
departure_day integer NOT NULL,
departure_hour integer NOT NULL,
departure_minute integer NOT NULL,
arrival_day integer NOT NULL,
arrival_hour integer NOT NULL,
arrival_minute integer NOT NULL,
hidden boolean NOT NULL DEFAULT false,
deleted boolean NOT NULL DEFAULT false,
CONSTRAINT unique_origin_destination_per_route UNIQUE (route_id, origin_id, destination_id)
);
And here is my error:
ERROR: syntax error at or near "from"
LINE 1: ...pdate set departure_hour = c.departure_hour from (valu...

You don't need the from part in order to be able to reference the values to update.
insert into segments(id, departure_hour)
values
(1153, 2),
(1156, 4),
(1154, 2)
on conflict do update set
departure_hour = excluded.departure_hour;

Related

postgreSQL syntax error at or near "foreign"

I get the following error of "syntax error at or near "foreign"" when trying to create kurinys table. Might be a silly mistake but I can't recognize it. Thank you in advance.
create table elba7430.kurinys(
id INTEGER not null check (id > 10000),
pavadinimas VARCHAR (55) not null,
metai YEAR,
meno_rusies_id INTEGER not null check (meno_rusies_id > 100),
autoriaus_id INTEGER not null check (autoriaus_id > 1000000),
kliento_id INTEGER not null check (kliento_id > 1000000),
ilgis_cm DECIMAL (100,2),
plotis_cm DECIMAL (100,2),
kaina DECIMAL (100,2),
primary key (id),
foreign key (meno_rusies_id)
REFERENCES elba7430.meno_rusis on delete cascade on update restrict,
foreign key (autoriaus_id)
REFERENCES elba7430.autorius on delete cascade on update restrict,
foreign key (kliento_id)
REFERENCES elba7430.klientas on delete cascade on update restrict
);
create table elba7430.meno_rusis(
id INTEGER not null check (id > 100),
pavadinimas VARCHAR (100) not null,
primary key(id)
);
create table elba7430.autorius(
id INTEGER not null check (id > 1000000),
vardas VARCHAR (40) not null,
pavarde VARCHAR (55) not null,
gimimo_metai DATE,
primary key(id)
);
create table elba7430.klientas(
id INTEGER not null check (id > 1000000),
vardas VARCHAR (40),
pavarde VARCHAR (55),
primary key(id)
);
Changing the order of your declarations and replacing the year data type by a valid one will solve this issue, here you can replicate this: db<>fiddle

Constraint: Only one row must have a NULL value

Only one row is allowed to have parent_id NULL:
CREATE TABLE simple21_page (
id integer NOT NULL,
name character varying(120) NOT NULL,
text text NOT NULL,
parent_id integer
);
This is a tree and there should be exactly one root node.
I tried this, but it does not work:
create unique index on simple21_page (parent_id) where parent_id is null;
Is this possible with an constraint or unique index, or is a trigger needed?
You are almost there. To get a singleton, you need a unique constraint on a constant value:
CREATE UNIQUE INDEX ON simple21_page ((1)) WHERE parent_id IS NULL;
Another way to enforce this kind of uniqueness is usage of COALESCE and index on expression:
CREATE UNIQUE INDEX ON simple21_page(COALESCE(parent_id, -1));
The value provided as substitute should be out of scope of permitted values.
db<>fiddle demo
INSERT INTO simple21_page VALUES (1, 'a', 'text', NULL);
-- success
INSERT INTO simple21_page VALUES (2, 'b', 'text', NULL);
-- ERROR: duplicate key value violates unique constraint "simple21_page_coalesce_idx"

What is the code for a T-SQL check constraint?

I want to add a check clause to this table so that:
IF a transaction enters a value for the diastolicBloodPressure
THEN the transaction must also insert a value for the systolicBloodPressure.
CREATE TABLE "Constraint-BloodPressure".Patient
(
patientNr int NOT NULL,
diastolicBloodPressure smallint,
systolicBloodPressure smallint,
CONSTRAINT Patient_PK PRIMARY KEY(patientNr)
)
Is this correct?
CONSTRAINT CHK_BloodPressure CHECK (diastolicBloodPressure >0 AND systolicBloodPressure >0 )
You did not specify, whether your table would accept NULL-values and how you would deal with them.
Due to the kind of data, my suggestion was this:
CREATE TABLE dbo.TestCheck
(
patientNr INT NOT NULL CONSTRAINT PK_TestCheck PRIMARY KEY
,diastolicBloodPressure smallint NOT NULL
,systolicBloodPressure smallint NOT NULL
,CONSTRAINT chk_TestCheck_MustEnterBoth CHECK(diastolicBloodPressure BETWEEN 0 AND 250 AND systolicBloodPressure BETWEEN 0 AND 250)
);
--The table will not accept NULL-values and it will force the entered values to keep within realistic borders.
--Instead of smallint you might use tinyint, which is bordered between 0 and 255 by definition.
--Try the following:
INSERT INTO dbo.TestCheck VALUES(1,100,110);
GO
INSERT INTO dbo.TestCheck VALUES(2,100,NULL);
GO
INSERT INTO dbo.TestCheck VALUES(3,NULL,NULL);
GO
INSERT INTO dbo.TestCheck VALUES(4,-1,1000);
GO
SELECT * FROM dbo.TestCheck;
--Only the first insert will succeed, all the other attempts fill fail
--Clean-Up Carefull with real data...
GO
DROP TABLE dbo.TestCheck;
Not sure what database system you are using. On SQL Server 2014 I am require specify "NULL" or "NOT NULL". So my create table statement with the check constraint and insert statements looks like this...
IF OBJECT_ID('tempdb.dbo.#Patient', 'U') IS NOT NULL
DROP TABLE #Patient;
CREATE TABLE #Patient
(
patientNr INT NOT NULL
, diastolicBloodPressure SMALLINT NULL
, systolicBloodPressure SMALLINT NULL
, CONSTRAINT Patient_PK
PRIMARY KEY (patientNr)
, CHECK ((
diastolicBloodPressure IS NOT NULL
AND systolicBloodPressure IS NOT NULL
)
OR (
diastolicBloodPressure IS NULL
AND systolicBloodPressure IS NULL
)
)
);
INSERT INTO #Patient VALUES (1, NULL, NULL);
INSERT INTO #Patient VALUES (2, 120, NULL);
INSERT INTO #Patient VALUES (3, NULL, 80);
INSERT INTO #Patient VALUES (4, 120, 80);
The first and last insert statements work and the middle two fail.
If you want to force both fields to have a value, then you need to check for null values. If you don't, then your current check will allow entry of just the patientNbr or just one value.
CREATE TABLE dbo.Patient
(
patientNr int NOT NULL,
diastolicBloodPressure smallint,
systolicBloodPressure smallint,
CONSTRAINT Patient_PK PRIMARY KEY(patientNr),
CONSTRAINT CHK_BloodPressure CHECK (ISNULL(diastolicBloodPressure, 0) > 0 AND ISNULL(systolicBloodPressure, 0) > 0 )
);
GO
-- Valid
INSERT INTO dbo.Patient VALUES (1, 120, 80);
GO
-- Invalid
INSERT INTO dbo.Patient VALUES (2, 120, 0);
GO
-- Invalid
INSERT INTO dbo.Patient VALUES (3, 0, 80);
GO
-- Invalid
INSERT INTO dbo.Patient (patientNr, diastolicBloodPressure) VALUES (4, 120);
GO
-- Invalid
INSERT INTO dbo.Patient (patientNr) VALUES (5);
GO

How can i create check function in postgresql?

I would like to check in the table "PRENOTAZIONE" that the number of adults "n_adulti" is greater than 0 and less than max number of adults "n_max_adulti" in table "APPARTAMENTO".
This is the table PRENOTAZIONE
create table PRENOTAZIONE (
id_prenotazione serial,
data_inizio date not null,
data_fine date not null,
n_adulti smallint default 1,
n_bimbi smallint default 0,
n_neonati smallint default 0,
n_ospiti_extra smallint default 0,
appartamento integer not null,
cliente varchar(255),
primary key(id_prenotazione),
foreign key (appartamento)
references APPARTAMENTO(id_appartamento),
foreign key (cliente)
references CLIENTE(email)
);
and this is the table APPARTAMENTO
create table APPARTAMENTO (
id_appartamento serial,
sconti_mensili real default 0,
sconti_settimanali real default 0,
n_camere_letto smallint default 0,
n_letti smallint default 0,
n_posti_letto smallint default 0,
n_bagni smallint default 0,
orario_check_in time not null,
orario_check_out time not null,
n_max_bimbi smallint not null,
n_max_neonati smallint not null,
n_max_adulti smallint not null,
tipo varchar(255) not null,
descrizione varchar(100) default ' ',
ospiti_extra smallint default 0,
cauzione real default 0,
costi_pulizia real default 0,
costo_bimbo real default 0,
costo_adulto real default 0,
servizio varchar(255),
indirizzo integer,
proprietario varchar(255),
tipologia integer,
termine_cancellazione smallint default 1,
primary key(id_appartamento),
foreign key (indirizzo)
references INDIRIZZO(id_indirizzo),
foreign key (termine_cancellazione)
references TERMINE_DI_CANCELLAZIONE(id_termine),
foreign key (proprietario)
references PROPRIETARIO(email),
foreign key (tipologia)
references TIPOLOGIA_APPARTAMENTO(id_tipologia),
foreign key (servizio)
references SERVIZIO(servizio)
);
and this is the check operation i want to do
check ((n_adulti > 0) and (n_adulti <= (select n_max_adulti from APPARTAMENTO join PRENOTAZIONE on (id_appartamento = appartamento))))
and ((n_bimbi >= 0) and (n_bimbi <= (select n_max_bimbi from APPARTAMENTO join PRENOTAZIONE on (id_appartamento = appartamento))
and ((n_neonati > 0) and (n_neonati <= (select n_max_neonati from APPARTAMENTO join PRENOTAZIONE on (id_appartamento = appartamento)))))
but in PostgreSQL unfortunatly the sub query are not supported... and i need to do this with a trigger.
I looked something here: https://www.postgresql.org/docs/9.1/static/sql-createtrigger.html
and
https://www.tutorialspoint.com/postgresql/postgresql_triggers.htm
but i didn't find what i looking for...
I didn't understand how functions and triggers work together and how can I do this function.
PS: I'm sorry for the name of the tables but I'm Italian. However this database is a school project inspired by Airbnb.
The purpose was to create a similar and simplified database compared to Airbnb.
Create a trigger BEFORE INSERT OR UPDATE ON prenotazione FOR EACH ROW that calls the following PL/pgSQL trigger function:
Selects n_max_bimbi, n_max_neonati and n_max_adulti from the appartamento row that belongs to NEW.appartamento.
If NEW.n_adulti is not between 0 and the n_max_adulti found above, raise an appropriate exception. Similar for the others.

Default constraint not being enforced

Given the following table definition:
CREATE TABLE ControlledSubstances.NationalDrugCode
(
NationalDrugCodeID INT NOT NULL
,NationalDrugCode VARCHAR(20) NOT NULL
,Product VARCHAR(100)
,Ingredient VARCHAR(500)
,ClassID VARCHAR(50)
,Class VARCHAR(50)
,DrugEnforcementAgencyClassID VARCHAR(50)
,DrugEnforcementAgencyClass VARCHAR(50)
,GenericDrug VARCHAR(50)
,Form VARCHAR(50)
,Drug VARCHAR(50)
,StrengthPerUnit NUMERIC(6,2)
,UnitOfMeasure VARCHAR(50)
,ConversionFactor NUMERIC(4,2)
,LongOrShortActing VARCHAR(50)
,IsPreventionForStates BIT NOT NULL
)
;
ALTER TABLE ControlledSubstances.NationalDrugCode
ADD CONSTRAINT PK_ControlledSubstances_NationalDrugCode PRIMARY KEY (NationalDrugCodeID)
,CONSTRAINT DF_ControlledSubstances_NationalDrugCode_IsPreventionForStates DEFAULT 0 FOR IsPreventionForStates
;
CREATE UNIQUE INDEX UQ_ControlledSubstances_NationalDrugCode_NationalDrugCode ON ControlledSubstances.NationalDrugCode (NationalDrugCode);
Why would I be receiving an error on insert for the column I defined as NOT NULL and created a default constraint of 0? I know I can handle the logic in the insert statement to not pass in NULL values, but I use this logic in multiple tables and have never gotten an error before. The error I receive is:
Cannot insert the value NULL into column 'IsPreventionForStates', table 'Staging.ControlledSubstances.NationalDrugCode'; column does not allow nulls. INSERT fails.
This will happen if you explicitly provide NULL as its value. The default constraint only kicks in when you don't supply a value at all, or when you use the DEFAULT keyword:
For example, if NationalDrugCodeID and IsPreventionForStates were your only two columns in the table (for illustration), this will fail:
INSERT INTO NationalDrugCode(NationalDrugCodeID, IsPreventionForStates) VALUES (5, NULL);
But either of these would work:
INSERT INTO NationalDrugCode(NationalDrugCodeID) VALUES (5);
INSERT INTO NationalDrugCode(NationalDrugCodeID, IsPreventionForStates) VALUES (5, DEFAULT);
In the edge case where you need ALL columns to have default values inserted, you can use:
INSERT INTO NationalDrugCode DEFAULT VALUES;