vendredi 25 septembre 2015

Simulating UPSERT in presence of UNIQUE constraints

Simulating UPSERT was already discusssed before. In my case though, I have PRIMARY KEY and additional UNIQUE constraint, and I want upsert semantic with respect to primary key - replacing existing row if it exists, while checking the unique constraint.

Here's an attempt using insert-or-replace:

drop table if exists test;
create table test (id INTEGER, name TEXT, s INTEGER, 
                   PRIMARY KEY (id, s), 
                   UNIQUE (name, s));

insert or replace into test values (1, "a", 0);
insert or replace into test values (1, "a", 0);
insert or replace into test values (2, "b", 0);
insert or replace into test values (2, "a", 0);

The last statement is replaces both rows. This is documented behavior of 'insert or replace', but not what I want.

Here is an attempt with "on conflict replace":

drop table if exists test;
create table test (id INTEGER, name TEXT, s INTEGER, 
                   PRIMARY KEY (id, s) on conflict replace, 
                   UNIQUE (name, s));

insert into test values (1, "a", 0);
insert into test values (1, "a", 0);

I get "UNIQUE constraint failed" right away. The problem disappears if don't share column between both primary key and unique constraint:

drop table if exists test;
create table test (id INTEGER, name TEXT,
                   PRIMARY KEY (id) on conflict replace, 
                   UNIQUE (name));

insert into test values (1, "a");
insert into test values (1, "a");
insert into test values (2, "b");
insert into test values (2, "a");

Here, I get constraint violation on the very last statement, which is precisely right. Sadly, I do need to share a column between constraints.

Is this something I don't understand about SQL, or SQLite issue, and how do I get the desired effect, except for first trying insert and then doing update on failure?

Aucun commentaire:

Enregistrer un commentaire