219 lines
4.3 KiB
SQL
219 lines
4.3 KiB
SQL
# name: test/sql/upsert/upsert_basic.test
|
|
# group: [upsert]
|
|
|
|
statement ok
|
|
PRAGMA enable_verification;
|
|
|
|
statement ok
|
|
CREATE TABLE tbl(
|
|
i INT PRIMARY KEY,
|
|
j INT UNIQUE,
|
|
k INT
|
|
);
|
|
|
|
statement ok
|
|
INSERT INTO tbl VALUES (1, 10, 1), (2, 20, 1), (3, 30, 2);
|
|
|
|
# Update the on-conflict column.
|
|
statement ok
|
|
INSERT INTO tbl VALUES (3, 5, 1)
|
|
ON CONFLICT (i) DO UPDATE SET i = i + 1;
|
|
|
|
query III
|
|
SELECT i, j, k FROM tbl ORDER BY ALL;
|
|
----
|
|
1 10 1
|
|
2 20 1
|
|
4 30 2
|
|
|
|
query III
|
|
SELECT i, j, k FROM tbl WHERE i = 4;
|
|
----
|
|
4 30 2
|
|
|
|
# Update the on-conflict column again.
|
|
statement ok
|
|
INSERT INTO tbl VALUES (4, 30, 2)
|
|
ON CONFLICT (i) DO UPDATE SET i = i - 1;
|
|
|
|
query III
|
|
SELECT i, j, k FROM tbl ORDER BY ALL;
|
|
----
|
|
1 10 1
|
|
2 20 1
|
|
3 30 2
|
|
|
|
# Cannot update to the same PK value as another column.
|
|
statement error
|
|
INSERT INTO tbl VALUES (3, 30, 2)
|
|
ON CONFLICT (i) DO UPDATE SET i = i - 2;
|
|
----
|
|
<REGEX>:Constraint Error.*violates primary key constraint.*
|
|
|
|
# 'excluded' refers to the VALUES list, turning this into:
|
|
# (k)2 + (k.excluded)1 = 3
|
|
statement ok
|
|
insert into tbl VALUES
|
|
(3,5,1)
|
|
ON CONFLICT (i) DO UPDATE SET k = k + excluded.k;
|
|
|
|
query III
|
|
select * from tbl;
|
|
----
|
|
1 10 1
|
|
2 20 1
|
|
3 30 3
|
|
|
|
# The ON CONFLICT does not refer to a column that's indexed on, so it's never true
|
|
statement error
|
|
insert into tbl VALUES
|
|
(3,5,1)
|
|
ON CONFLICT (k) DO UPDATE SET k = excluded.k;
|
|
----
|
|
Binder Error: The specified columns as conflict target are not referenced by a UNIQUE/PRIMARY KEY CONSTRAINT
|
|
|
|
# Overwrite the existing value with the new value
|
|
statement ok
|
|
insert into tbl VALUES
|
|
(3,5,1)
|
|
ON CONFLICT (i) DO UPDATE SET k = excluded.k;
|
|
|
|
query III
|
|
select * from tbl;
|
|
----
|
|
1 10 1
|
|
2 20 1
|
|
3 30 1
|
|
|
|
# Don't alter the existing row, but still insert the non-conflicting row
|
|
statement ok
|
|
insert into tbl VALUES
|
|
(4,2,3),
|
|
(3,5,10)
|
|
ON CONFLICT (i) DO NOTHING;
|
|
|
|
query III
|
|
select * from tbl;
|
|
----
|
|
1 10 1
|
|
2 20 1
|
|
3 30 1
|
|
4 2 3
|
|
|
|
# Two rows cause a conflict, on the same existing row
|
|
# only the last one is used
|
|
statement ok
|
|
insert into tbl VALUES
|
|
(3,3,10),
|
|
(3,3,10)
|
|
ON CONFLICT (i) DO UPDATE SET
|
|
k = excluded.k;
|
|
|
|
query III
|
|
select * from tbl order by all
|
|
----
|
|
1 10 1
|
|
2 20 1
|
|
3 30 10
|
|
4 2 3
|
|
|
|
# condition is not matched - no updates have happened
|
|
query I
|
|
insert into tbl VALUES (3,5,1) ON CONFLICT (i) DO UPDATE SET k = 1 WHERE k < 5;
|
|
----
|
|
0
|
|
|
|
query III
|
|
select * from tbl;
|
|
----
|
|
1 10 1
|
|
2 20 1
|
|
3 30 10
|
|
4 2 3
|
|
|
|
# When the condition is met, the DO is performed
|
|
query I
|
|
insert into tbl VALUES (3,5,1) ON CONFLICT (i) DO UPDATE SET k = 1 WHERE k >= 5;
|
|
----
|
|
1
|
|
|
|
# 'k' in row_id:3 is updated to 1
|
|
query III
|
|
select * from tbl;
|
|
----
|
|
1 10 1
|
|
2 20 1
|
|
3 30 1
|
|
4 2 3
|
|
|
|
# When the condition is on the DO UPDATE part,
|
|
# it will always succeed, but turn into a DO NOTHING for the conflicts that don't meet the condition
|
|
|
|
statement ok
|
|
insert into tbl VALUES (3,5,3) on conflict (i) do update set k = 10 WHERE k != 1;
|
|
|
|
# Unchanged, because the where clause is not met
|
|
query III
|
|
select * from tbl;
|
|
----
|
|
1 10 1
|
|
2 20 1
|
|
3 30 1
|
|
4 2 3
|
|
|
|
statement ok
|
|
insert into tbl VALUES (3,5,3) on conflict (i) do update set k = 10 WHERE k == 1;
|
|
|
|
# Changed, because the where clause is met
|
|
query III
|
|
select * from tbl;
|
|
----
|
|
1 10 1
|
|
2 20 1
|
|
3 30 10
|
|
4 2 3
|
|
|
|
# When we don't specify a conflict target, all unique/primary key constraints are used as the conflict target
|
|
statement ok
|
|
insert into tbl VALUES (5,1,0), (3,5,20) ON CONFLICT DO NOTHING;
|
|
|
|
query III
|
|
select * from tbl;
|
|
----
|
|
1 10 1
|
|
2 20 1
|
|
3 30 10
|
|
4 2 3
|
|
5 1 0
|
|
|
|
# Not supported because:
|
|
# > It's because one insert row could violate multiple different unique constraints,
|
|
# with it being a different row for each of the constraints that's causing the violation,
|
|
# and the upsert is only intended to update a single row.
|
|
# https://sqlite.org/forum/info/45cf84d3e89d590d
|
|
statement error
|
|
insert into tbl VALUES (5,1,0), (3,5,20) ON CONFLICT DO UPDATE set k = excluded.k;
|
|
----
|
|
Binder Error: Conflict target has to be provided for a DO UPDATE operation when the table has multiple UNIQUE/PRIMARY KEY constraints
|
|
|
|
statement ok
|
|
create or replace table single_constraint (
|
|
i integer PRIMARY KEY,
|
|
j integer,
|
|
k varchar,
|
|
);
|
|
|
|
statement ok
|
|
insert into single_constraint values (5,1,'hello'), (1,10,'test');
|
|
|
|
# This is however accepted if only a single constraint exists on the table
|
|
statement ok
|
|
insert into single_constraint values (1,5,'bye'), (3,10,'quack') on conflict do update set j = excluded.j, k = concat(k, excluded.k);
|
|
|
|
query III
|
|
select * from single_constraint
|
|
----
|
|
5 1 hello
|
|
1 5 testbye
|
|
3 10 quack
|