Constraint: Only one row must have a NULL value - postgresql

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"

Related

MySQL Error 1136:Column count does not match value count at row 1?

CREATE TABLE IF NOT EXISTS actores(
id_actor INT NOT NULL,
nombre VARCHAR(45) NOT NULL,
nacionalidad VARCHAR(45),
nombre_personaje VARCHAR(45),
PRIMARY KEY(id_actor)
)ENGINE=InnoDB;
INSERT INTO actores (nombre, nacionalidad)
VALUES ('Will smith' 'Americano');
You are missing a comma separating the values you want to insert.
VALUES ('Will smith', 'Americano');
You should change the definition for the field id_actor too to use auto-increment. Otherwise, you will need to specify an id for every insertion.
ALTER TABLE `actores`
CHANGE COLUMN `id_actor` `id_actor` INT(11) NOT NULL AUTO_INCREMENT ;

Postgresql: how to create types in postgresql

I am new to postgresql. I want to create types in SQL with below values but got stuck to create the same.
I understand its similar like table but I am unable to figure out the solution.
I want to create following types using postgresql
"Completed", "Pending", "Failed", "Created"
The correct way to do this, is to use a lookup table and a foreign key:
create table status
(
id integer primary key,
name text not null
);
insert into status (id, name)
values
(1, 'Completed'),
(2, 'Pending'),
(3, 'Failed'),
(4, 'Created');
create table some_table
(
id integer primary key,
status_id integer not null references status
);
That is the most flexible way to handle this in a relational database.
If you know that you will hardly ever change those values, you can use a check constraint:
create table some_table
(
id integer primary key,
status text not null,
constraint check_status
status in ('Completed', 'Pending', 'Failed', 'Created')
);
This has the disadvantage that you are storing the same values over and over again, so the size of the table will be bigger compared to the foreign key solution.
The third option is to use an enum type
create type status_type AS ENUM (''Completed', 'Pending', 'Failed', 'Created');
Then use that type in the table:
create table some_table
(
id integer primary key,
status status_type not null
);
This has a similar storage requirement as the foreign key solution but displays the status as "clear text".
CREATE TYPE color AS ENUM ('red', 'green', 'blue');

update order column based on groupby postgresql

I have created an order-column and i want to update the current values that is in that table.
CREATE TABLE public.publishroomcontacts
(
id integer NOT NULL DEFAULT nextval('publishroomcontacts_id_seq'::regclass),
publishroomid integer NOT NULL,
contactorder integer NOT NULL,
CONSTRAINT publishroomcontacts_pkey PRIMARY KEY (id),
CONSTRAINT fk_publishroomcontacts_publishroom_id FOREIGN KEY (publishroomid)
REFERENCES public.publishrooms (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE
)
WITH (
OIDS = FALSE
);
What i want to do is to go through all rows, group by publishroomid and add a contactorder.
So if there is 4 contacts with the same publishroomid whey will have contact order 1, 2, 3 and 4.
How do i do this?
EDIT:

PostgreSQL, config table constraint

I have table represents config for some companies:
id
config_id
company_id
Record in table means that config with number for instance 1 enabled for company for instance number 1. If company_id is null - that means given config enabled for all companies.
I need to create constraint(s) for given config_id there can be only one record with company_id = null, or multiple, but unique company_id which is not null.
Something like that does not fix up the problem:
CREATE UNIQUE INDEX config_unique_all_companies
ON company_config_relations (config_id)
WHERE company_id IS NULL
CREATE UNIQUE INDEX config_company_unique
ON company_config_relations (config_id, company_id)
WHERE company_id IS NOT NULL
Try the following:
CREATE UNIQUE INDEX config_unique_idx
ON company_config_relations (config_id, company_id)
WHERE config_id IS NOT NULL AND company_id IS NOT NULL;
CREATE UNIQUE INDEX config_unique_companies_idx
ON company_config_relations (company_id)
WHERE config_id IS NULL;
CREATE UNIQUE INDEX config_unique_default_config_idx
ON company_config_relations (COALESCE(config_id, 0))
WHERE company_id IS NULL AND config_id IS NULL;
The last one is the most interesting one. It creates an index containing just one element with a constant value. COALESCE(config_id, 0) is always 0. It is a trick to create a constant index value, because ... ON company_config_relations (0) ... will not work.

PostgreSQL there is no unique or exclusion constraint matching the ON CONFLICT specification

I am creating a table like this:
CREATE TABLE artist (
Id serial PRIMARY KEY,
NameNormalized varchar(256) NOT NULL UNIQUE,
Name text NOT NULL,
MusicBrainzId char(36) NULL,
Rating DECIMAL(2,1),
CONSTRAINT non_empty CHECK (length(NameNormalized) > 0 and length(Name) > 0)
);
When I try to execute the following INSERT operation, I get an error:
INSERT INTO artist (NameNormalized, Name, MusicBrainzId, Rating)
VALUES ('test', 'Test', '123456789012345678901234567890123456', 0.5)
ON CONFLICT (NameNormalized) DO NOTHING;
The error message is as follows:
ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
I have done some research but to my knowledge, setting NameNormalized to UNIQUE should be enough for ON CONFLICT to work. Also I am pretty sure this has worked in the past for me.