PostgreSQL multiple on conflicts in one upsert statement - postgresql

I have two unique constraints on the same table, and I want to do an upsert statement on that table.
Is it possible to specify the two conflicts in the upsert? I saw this: How to upsert in Postgres on conflict on one of 2 columns?
but my issue is slightly more involved because one of the unique constraints is a subset of the other unique constraint. I.e.
unique_constraint_1 = (col_1)
unqiue_constraint_2 = (col_1, col_2)
INSERT INTO table (col_1, col_2, col_3)
VALUES (val_1, val_2, val_3)
ON CONFLICT (what do I put here to account for both constraints?)
DO NOTHING;
thanks!

According to documentation, ON CONFLICT covers all unique constraints by default.
when omitted, conflicts with all usable constraints (and unique indexes) are handled
In your case there is no need for two constraints, as Grzegorz Grabek pointed out already. That is because the stricter single-column constraint already covers the looser two-column constraint.

Related

Postgres create table like exclude constraints but include indexes

I am trying to recreate a table's structure using following statement. However I would like to exclude constraints but include indexes from the original table.
CREATE TABLE users_audit (like users EXCLUDING CONSTRAINTS);
Above statement works as expected as it create a new table users_audit without constraints. However I am not sure if it is possible to copy indexes using INCLUDING INDEXES or even include everything except primary key constraint. Looking at the documentation it seems like I can only pass EXCLUDING | INCLUDING.
You can say
CREATE TABLE users_audit (like users EXCLUDING CONSTRAINTS INCLUDING INDEXES);
That will create all indexes, so it also will create the indexes that implement primary key and unique constraints. However, foreign key constraints won't be created.
There is no way to only create the indexes that do not belong to a constraint. For that, you could say INCLUDING INDEXES and afterwards drop all constraints.

UPSERT in PGSQL (version 11,)does the unique constraint be maintained always?

For ON CONFLICT(col) clause in UPSERT, should there be unique constraint for the column or combination of columns.
for eg:
if I have a simple table create table test(id integer ,name text ),Will I not be able to do UPSERT ?the UNIQUENESS constraint have to be enforced ?
Please help as I am confused.
A unique constraint must be fulfilled at the end of a transaction. So it can't become non-unique - you would get an error and the transaction would be rolled back. UPSERT can't fail:
ON CONFLICT DO UPDATE guarantees an atomic INSERT or UPDATE outcome;
provided there is no independent error, one of those two outcomes is
guaranteed, even under high concurrency. This is also known as UPSERT
— “UPDATE or INSERT”.

How to upsert in Postgres on conflict on one of 2 columns?

Is it possible to do upsert in Postgres 9.5 when conflict happens on one of 2 columns in a table.? Basically I have 2 columns and if either column throws unique constraint violation, then I would like to perform update operation.
Yes, and this behaviour is default. Any unique constraint violation constitutes a conflict and then the UPDATE is performed if ON CONFLICT DO UPDATE is specified. The INSERT statement can have only a single ON CONFLICT clause, but the conflict_target of that clause can specify multiple column names each of which must have an index, such as a UNIQUE constraint. You are, however, limited to a single conflict_action and you will not have information on which constraint caused the conflict when processing that action. If you need that kind of information, or specific action depending on the constraint violation, you should write a trigger function but then you lose the all-important atomicity of the INSERT ... ON CONFLICT DO ... statement.
I think in Postgres 9.5 ON CONFLICT can have only one constraint or multiple column names but on that multiple columns must have combine one index

Conditional PostgreSQL foreign key

Is it possible in PostgreSQL to conditionally add a foreign key?
Something like:ALTER TABLE table1 ADD FOREIGN KEY (some_id) REFERENCES other_table WHERE some_id NOT IN (0,-1) AND some_id IS NOT NULL;
Specifically, my reference table has all positive integers (1+) but the table I need to add the foreign key to can contain zero (0), null and negative one (-1) instead, all meaning something different.
Notes:
I am fully aware that this is poor table design, but it was a clever trick built 10+ years ago when the features and resources we have available at this point did not exist. This system is running hundreds of retail stores so going back and changing the method at this point could take months which we don't have.
I can not use a trigger, this MUST be done with a foreign key.
The short answer is no, Postgres does not have conditional foreign keys. Some options you might consider are:
Just not have a FK constraint. Move this logic into the data access layer and live without the referential integrity.
Allow NULL in the column, which is perfectly valid even with a FK constraint. Then, use another column to store whatever the meaning of 0 and -1 is.
Add a dummy row in the referenced table for 0 and -1. Even if it just had bogus data, it would satisfy the FK constraint.
Hope this helps!
You can add another "shadow" column to table1 which holds the cleaned values (i.e. everything but 0 and -1). Use this column for the referential integrity checks. This shadow column is updated/filled by a simple trigger on table1 which writes all values but 0 and -1 into the shadow column. Both 0 and -1 could be mapped to null.
Then you have reference integrity and your unchanged original column. The downside: You have also a little trigger and some redundant data. But alas, this is the fate of a legacy schema!
Your requirement is equivalent to this check constraint:
create table t (a float check (a >= -1 and a = floor(a) or a is null));
You can implement this with a check constraint and a foreign key.
CREATE TABLE table1 (some_id INT, some_id_fkey INT REFERENCES other_table(other_id), CHECK (some_id IN (0,-1) OR some_id IS NOT DISTINCT FROM some_id_fkey));
(not tested)
Here's another possibility. Use PG Inheritance to enforce a partition of the table into has +1 in the flag column and otherwise. (Usual rules/triggers for maintaining this.) Then have the FK relationship between only the Has_PLUS_ONE child table and the referenced table.

DB associative entities and indexing

This is kind of a general DB design question. If one has an associative entity table, i.e. a cross-reference, containing records that basically just consist of two FK references, should it be indexed in some way? Is it necessary to explicitly index that table, since the PKs in the associated tables are already indexed by definition? If one should index it, should it be a combination index, consisting of the two FK fields together?
Indexes on the referenced pk columns in the other tables do not cover it.
By defining the two fk columns as composite primary key of the "associative entity" table (as you should in most cases - provided that associations are unique), you implicitly create a multi-column index.
That covers all queries involving both or the first columns optimally.
It also covers queries on the second column, but in a less effective way.
If you have important queries involving just the second column, create an additional index on that one, too.
Read all the details about the topic at this related question on dba.SE.
Or this question on SO, also covering this topic.
Suppose your associative table has a schema such as:
CREATE TABLE Association
(
ReferenceA INTEGER NOT NULL REFERENCES TableA CONSTRAINT FK1_Association,
ReferenceB INTEGER NOT NULL REFERENCES TableB CONSTRAINT FK2_Association,
PRIMARY KEY(ReferenceA, ReferenceB) CONSTRAINT PK_Association
);
The chances are that your DBMS will automatically create some indexes.
Some DBMS will create an index for each of the two foreign keys and also a unique index for the primary key. This is slightly wasteful since the PK index could be used for accessing ReferenceA too.
Ideally, there will be just two indexes: the PK (unique) index and the (duplicates allowed) FK index for ReferenceB, assuming that the PK index has ReferenceA as the first column.
If a DBMS does not automatically create indexes to enforce the referential integrity constraints, you'll want to create the RI or FK duplicates-allowed index. If it doesn't automatically create an index to enforce the PK constraint, you'll want to create that unique index too. The upside is that you'll only create the indexes for the ideal case.
Depending on your DBMS, you might find it more effective to create the table without the constraints, then to add the indexes, and then to add the constraints (which will then use the indexes you created). Things like fragmentation schemes can also factor into this; I ignored them above.
The concept remains simple — you want two indexes in total, one to enforce uniqueness on both columns and provide fast access on the leading column, and a non-unique or duplicates-allowed index on the trailing column.