Postgres UPSERT syntax confusion - postgresql

I have a table with 2 columns:
channels TEXT
rowid INTEGER PRIMARY KEY
I included an index on channels
CREATE UNIQUE INDEX channels_index on mytable (lower(channels))
so that VisitToronto will be a conflict with visittoronto
All works well and the conflict fires.
ERROR: duplicate key value violates unique constraint "channels_index"
DETAIL: Key (lower(words))=(hello world) already exists.
I can not figure out the syntax to trap this conflict. ON CONFLICT channels doesn't work ON CONFLICT ON CONSTRAINT channels_index doesn't work
The closest I've got is:
ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
Any direction would be appreciated.
TIA

Use the index expression, i.e. lower(channels):
insert into my_table (channels) values
('VisitToronto');
insert into my_table (channels)
values ('visittoronto')
on conflict (lower(channels)) do
update set channels = excluded.channels;
select *
from my_table;
id | channels
----+--------------
1 | visittoronto
(1 row)
You are not able to use a constraint because the index is on an expression. In the case Postgres cannot create a constraint:
alter table my_table add constraint channels_unique unique using index channels_index;
ERROR: index "channels_index" contains expressions
LINE 1: alter table my_table add constraint channels_unique unique u...
^
DETAIL: Cannot create a primary key or unique constraint using such an index.

Related

there is no unique constraint matching given keys for referenced table "employees" [duplicate]

Trying to create this example table structure in Postgres 9.1:
CREATE TABLE foo (
name VARCHAR(256) PRIMARY KEY
);
CREATE TABLE bar (
pkey SERIAL PRIMARY KEY,
foo_fk VARCHAR(256) NOT NULL REFERENCES foo(name),
name VARCHAR(256) NOT NULL,
UNIQUE (foo_fk,name)
);
CREATE TABLE baz(
pkey SERIAL PRIMARY KEY,
bar_fk VARCHAR(256) NOT NULL REFERENCES bar(name),
name VARCHAR(256)
);
Running the above code produces an error, which does not make sense to me:
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
NOTICE: CREATE TABLE will create implicit sequence "bar_pkey_seq" for serial column "bar.pkey"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "bar_pkey" for table "bar"
NOTICE: CREATE TABLE / UNIQUE will create implicit index "bar_foo_fk_name_key" for table "bar"
NOTICE: CREATE TABLE will create implicit sequence "baz_pkey_seq" for serial column "baz.pkey"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "baz_pkey" for table "baz"
ERROR: there is no unique constraint matching given keys for referenced table "bar"
********** Error **********
ERROR: there is no unique constraint matching given keys for referenced table "bar"
SQL state: 42830
Can anyone explain why this error arises?
It's because the name column on the bar table does not have the UNIQUE constraint.
So imagine you have 2 rows on the bar table that contain the name 'ams' and you insert a row on baz with 'ams' on bar_fk, which row on bar would it be referring since there are two rows matching?
In postgresql all foreign keys must reference a unique key in the parent table, so in your bar table you must have a unique (name) index.
See also http://www.postgresql.org/docs/9.1/static/ddl-constraints.html#DDL-CONSTRAINTS-FK and specifically:
Finally, we should mention that a foreign key must reference columns
that either are a primary key or form a unique constraint.
Emphasis mine.
You should have name column as a unique constraint. here is a 3 lines of code to change your issues
First find out the primary key constraints by typing this code
\d table_name
you are shown like this at bottom "some_constraint" PRIMARY KEY, btree (column)
Drop the constraint:
ALTER TABLE table_name DROP CONSTRAINT some_constraint
Add a new primary key column with existing one:
ALTER TABLE table_name ADD CONSTRAINT some_constraint PRIMARY KEY(COLUMN_NAME1,COLUMN_NAME2);
That's All.
when you do UNIQUE as a table level constraint as you have done then what your defining is a bit like a composite primary key see ddl constraints, here is an extract
This specifies that the combination of values in the indicated columns is unique across the whole table, though any one of the columns need not be (and ordinarily isn't) unique.
this means that either field could possibly have a non unique value provided the combination is unique and this does not match your foreign key constraint.
most likely you want the constraint to be at column level. so rather then define them as table level constraints, 'append' UNIQUE to the end of the column definition like name VARCHAR(60) NOT NULL UNIQUE or specify indivdual table level constraints for each field.

ERROR: there is no unique constraint matching given keys for referenced table "mail_message" Odoo Postgres [duplicate]

Trying to create this example table structure in Postgres 9.1:
CREATE TABLE foo (
name VARCHAR(256) PRIMARY KEY
);
CREATE TABLE bar (
pkey SERIAL PRIMARY KEY,
foo_fk VARCHAR(256) NOT NULL REFERENCES foo(name),
name VARCHAR(256) NOT NULL,
UNIQUE (foo_fk,name)
);
CREATE TABLE baz(
pkey SERIAL PRIMARY KEY,
bar_fk VARCHAR(256) NOT NULL REFERENCES bar(name),
name VARCHAR(256)
);
Running the above code produces an error, which does not make sense to me:
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
NOTICE: CREATE TABLE will create implicit sequence "bar_pkey_seq" for serial column "bar.pkey"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "bar_pkey" for table "bar"
NOTICE: CREATE TABLE / UNIQUE will create implicit index "bar_foo_fk_name_key" for table "bar"
NOTICE: CREATE TABLE will create implicit sequence "baz_pkey_seq" for serial column "baz.pkey"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "baz_pkey" for table "baz"
ERROR: there is no unique constraint matching given keys for referenced table "bar"
********** Error **********
ERROR: there is no unique constraint matching given keys for referenced table "bar"
SQL state: 42830
Can anyone explain why this error arises?
It's because the name column on the bar table does not have the UNIQUE constraint.
So imagine you have 2 rows on the bar table that contain the name 'ams' and you insert a row on baz with 'ams' on bar_fk, which row on bar would it be referring since there are two rows matching?
In postgresql all foreign keys must reference a unique key in the parent table, so in your bar table you must have a unique (name) index.
See also http://www.postgresql.org/docs/9.1/static/ddl-constraints.html#DDL-CONSTRAINTS-FK and specifically:
Finally, we should mention that a foreign key must reference columns
that either are a primary key or form a unique constraint.
Emphasis mine.
You should have name column as a unique constraint. here is a 3 lines of code to change your issues
First find out the primary key constraints by typing this code
\d table_name
you are shown like this at bottom "some_constraint" PRIMARY KEY, btree (column)
Drop the constraint:
ALTER TABLE table_name DROP CONSTRAINT some_constraint
Add a new primary key column with existing one:
ALTER TABLE table_name ADD CONSTRAINT some_constraint PRIMARY KEY(COLUMN_NAME1,COLUMN_NAME2);
That's All.
when you do UNIQUE as a table level constraint as you have done then what your defining is a bit like a composite primary key see ddl constraints, here is an extract
This specifies that the combination of values in the indicated columns is unique across the whole table, though any one of the columns need not be (and ordinarily isn't) unique.
this means that either field could possibly have a non unique value provided the combination is unique and this does not match your foreign key constraint.
most likely you want the constraint to be at column level. so rather then define them as table level constraints, 'append' UNIQUE to the end of the column definition like name VARCHAR(60) NOT NULL UNIQUE or specify indivdual table level constraints for each field.

INSERT INTO excluding ID column violates primary key uniqueness constraint

I have a Postgres 10.6 table with a serial ID column.
When I attempt to insert into it:
INSERT INTO table (col1, col2) VALUES ('foo', 'bar');
excluding the ID column from the column list, I get:
ERROR: duplicate key value violates unique constraint "customer_invoice_pkey"
Detail: Key (id)=(1234) already exists.
Subsequent runs of the query increment the ID in the error message (1235, 1236 etc.)
How can this be happening?
Having a serial column does not prevent you from inserting rows with an explicit value for id. The sequence value is only a default value that is used when id is not specified in the INSERT statement.
So there must have been some “rogue” inserts of that kind. From PostgreSQL v11 on, you can use identity columns (GENERATED ALWAYS AS IDENTITY) to make overriding the sequence value harder.
You could use the setval function to set the sequence to a value higher than the maximum id in the table to work around the problem.

Alter the table by adding constraint and using index in postgresql getting an error syntax error at or near "("IDX_emp_PK

CREATE INDEX IDX_emp_PK ON
EMP(ID);
ALTER TABLE EMP ADD
CONSTRAINT PK_emp PRIMARY KEY (ID)
USING INDEX IDX_emp_PK;
There are two errors in your script:
First: you can't use a non-unique index for a primary key constraint, so you need
CREATE UNIQUE INDEX idx_emp_pk ON emp(id);
When you add a primary or unique constraint based on an index, you can't specify columns (as they are already defined in the index):
ALTER TABLE emp ADD
CONSTRAINT pk_emp PRIMARY KEY
USING INDEX idx_emp_pk;

Duplicate key during import in PostgreSQL

I am following an PostgreSQL book, and had to import a CSV file into a table census.lu_tracts.
Problem: When performing the INSERT query as shown below, I get the error:
ERROR: duplicate key value violates unique constraint "pk_lu_tracts"
DETAIL: Key (tract_id)=(25001010800) already exists.
How did the key becomes duplicate? SELECT * from lu_tracs shows 0 rows.
CREATE SCHEMA census;
set search_path=census;
CREATE TABLE lu_tracts(tract_id varchar(11), tract_long_id varchar(25)
, tract_name varchar(150)
, CONSTRAINT pk_lu_tracts PRIMARY KEY (tract_id));
INSERT INTO lu_tracts( tract_id, tract_long_id, tract_name)
SELECT geo_id2, geo_id, geo_display
FROM staging.factfinder_import
WHERE geo_id2 ~ '^[0-9]+';
The right answer is DISTINCT ON (geo_id2) which will select only one row per geo_id2 (more in the manual), it should be accompanied by an ORDER BY clause that will specify what row will be choosen.