upsert 冲突目标中的 Where 子句
Where clause in upsert conflict target
假设我有一个这样创建的table:
CREATE TABLE actions (name text primary key, value text);
INSERT INTO actions (name) VALUES ('bla');
尝试插入新行时,有三种可能:
- 不存在 'name' 的行。应插入新行。
- 'name' 的一行存在值为 NULL。现有行应该是
更新为新值。
- 'name ' 的一行存在非 NULL 值。插入应该会失败。
我认为我应该能够像这样使用 UPSERT 语法:
INSERT INTO actions (name, value) values ('bla', 'val1')
ON CONFLICT(name) WHERE value IS NULL
DO UPDATE SET value = excluded.value;
INSERT INTO actions (name, value) values ('bla', 'val2')
ON CONFLICT(name) WHERE value IS NULL
DO UPDATE SET value = excluded.value;
第一个命令按预期更新现有行。但是第二个命令又更新了这一行,这是我没想到的。
冲突目标中的 where 子句应该做什么?在我的测试中,它的计算结果是真还是假似乎并不重要。
基于,我尝试使用唯一的部分索引而不是主键,但最终我得到了多个同名行。
我觉得这像是一个错误。但您可以轻松解决它:
INSERT INTO actions (name, value) values ('bla', 'val1')
ON CONFLICT(name)
DO UPDATE SET value = COALESCE(value, excluded.value);
Here 是一个 db<>fiddle.
使用 second WHERE
将执行您想要的操作:
INSERT INTO actions(name) VALUES ('bla');
INSERT INTO actions(name, value) VALUES ('bla', 'val1')
ON CONFLICT(name) DO UPDATE SET value = excluded.value WHERE value IS NULL;
SELECT * FROM actions;
name value
---------- ----------
bla val1
INSERT INTO actions(name, value) VALUES ('bla', 'val2')
ON CONFLICT(name) DO UPDATE SET value = excluded.value WHERE value IS NULL;
SELECT * FROM actions;
name value
---------- ----------
bla val1
冲突列之后的第一个 WHERE
用于 select 用于检测冲突的特定部分索引。举个例子给大家感受一下:
sqlite> CREATE TABLE ex(name, value1, value2);
sqlite> CREATE UNIQUE INDEX ex_idx_name ON ex(name) WHERE value1 IS NULL;
sqlite> INSERT INTO ex(name) VALUES ('bla');
sqlite> INSERT INTO ex(name, value2) VALUES ('bla', 'val1');
Error: UNIQUE constraint failed: ex.name
sqlite> INSERT INTO ex(name, value1, value2) VALUES ('bla', 1, 'val2');
sqlite> SELECT * from ex;
name value1 value2
---------- ---------- ----------
bla (null) (null)
bla 1 val2
sqlite> INSERT INTO ex(name, value2) VALUES ('bla', 'val3')
...> ON CONFLICT(name) WHERE value1 IS NULL DO UPDATE SET value2 = excluded.value2;
sqlite> SELECT * from ex;
name value1 value2
---------- ---------- ----------
bla (null) val3
bla 1 val2
sqlite> INSERT INTO ex(name, value2) VALUES ('bla', 'val4')
...> ON CONFLICT(name) DO UPDATE SET value2 = excluded.value2;
Error: ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint
请特别注意最后两个 INSERT
:第一个使用空值更新行,第二个生成错误,因为它没有完全指定唯一索引。
假设我有一个这样创建的table:
CREATE TABLE actions (name text primary key, value text);
INSERT INTO actions (name) VALUES ('bla');
尝试插入新行时,有三种可能:
- 不存在 'name' 的行。应插入新行。
- 'name' 的一行存在值为 NULL。现有行应该是 更新为新值。
- 'name ' 的一行存在非 NULL 值。插入应该会失败。
我认为我应该能够像这样使用 UPSERT 语法:
INSERT INTO actions (name, value) values ('bla', 'val1')
ON CONFLICT(name) WHERE value IS NULL
DO UPDATE SET value = excluded.value;
INSERT INTO actions (name, value) values ('bla', 'val2')
ON CONFLICT(name) WHERE value IS NULL
DO UPDATE SET value = excluded.value;
第一个命令按预期更新现有行。但是第二个命令又更新了这一行,这是我没想到的。
冲突目标中的 where 子句应该做什么?在我的测试中,它的计算结果是真还是假似乎并不重要。
基于
我觉得这像是一个错误。但您可以轻松解决它:
INSERT INTO actions (name, value) values ('bla', 'val1')
ON CONFLICT(name)
DO UPDATE SET value = COALESCE(value, excluded.value);
Here 是一个 db<>fiddle.
使用 second WHERE
将执行您想要的操作:
INSERT INTO actions(name) VALUES ('bla');
INSERT INTO actions(name, value) VALUES ('bla', 'val1')
ON CONFLICT(name) DO UPDATE SET value = excluded.value WHERE value IS NULL;
SELECT * FROM actions;
name value
---------- ----------
bla val1
INSERT INTO actions(name, value) VALUES ('bla', 'val2')
ON CONFLICT(name) DO UPDATE SET value = excluded.value WHERE value IS NULL;
SELECT * FROM actions;
name value
---------- ----------
bla val1
冲突列之后的第一个 WHERE
用于 select 用于检测冲突的特定部分索引。举个例子给大家感受一下:
sqlite> CREATE TABLE ex(name, value1, value2);
sqlite> CREATE UNIQUE INDEX ex_idx_name ON ex(name) WHERE value1 IS NULL;
sqlite> INSERT INTO ex(name) VALUES ('bla');
sqlite> INSERT INTO ex(name, value2) VALUES ('bla', 'val1');
Error: UNIQUE constraint failed: ex.name
sqlite> INSERT INTO ex(name, value1, value2) VALUES ('bla', 1, 'val2');
sqlite> SELECT * from ex;
name value1 value2
---------- ---------- ----------
bla (null) (null)
bla 1 val2
sqlite> INSERT INTO ex(name, value2) VALUES ('bla', 'val3')
...> ON CONFLICT(name) WHERE value1 IS NULL DO UPDATE SET value2 = excluded.value2;
sqlite> SELECT * from ex;
name value1 value2
---------- ---------- ----------
bla (null) val3
bla 1 val2
sqlite> INSERT INTO ex(name, value2) VALUES ('bla', 'val4')
...> ON CONFLICT(name) DO UPDATE SET value2 = excluded.value2;
Error: ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint
请特别注意最后两个 INSERT
:第一个使用空值更新行,第二个生成错误,因为它没有完全指定唯一索引。