upsert冲突目标中的where子句

问题描述 投票:0回答:3

假设我有一个这样创建的表:

CREATE TABLE actions (name text primary key, value text);
INSERT INTO actions (name) VALUES ('bla');

尝试插入新行时,有以下三种可能性:

  1. 不存在“名称”行。应该插入新行。
  2. 存在'name'的行,其值为NULL。现有行应为已使用新值更新。
  3. 存在'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子句应该做什么?在我的测试中,它的值为true或false似乎无关紧要。

基于PostgreSQL Upsert with a WHERE clause,我尝试使用唯一的部分索引而不是主键,但是最后我得到了多个具有相同名称的行。

sql sqlite upsert
3个回答
0
投票

对我来说这似乎是个虫子。但是您可以轻松解决它:

INSERT INTO actions (name, value) values ('bla', 'val1')
ON CONFLICT(name) 
DO UPDATE SET value = COALESCE(value, excluded.value);

Here是db <>小提琴。


0
投票

ON CONFLICT子句在检测到冲突后立即被调用,而与列的值无关。因此,您无法根据值决定以后是否进行更新或失败(即引发错误)。

一种解决方法是使用CASE表达式仅分配先前是NULL的新值:

INSERT INTO actions (name, value) values ('bla', 'val2')
ON CONFLICT(name)
DO UPDATE SET value = CASE WHEN value IS NULL THEN excluded.value ELSE value END;

如果初始值不为null,这不会失败,但这也不会正确分配新值。


0
投票

我无法在语法图中实际上任何地方实际记录的冲突子句后立即找到WHERE(但是,如果它的作用类似于Postgres,则表示不使用的部分索引;仍在研究之中) 。但是,使用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

0
投票

UPSERT的文档没有阐明“冲突目标”]内的UPSERT子句的使用,但是您可以通过删除该WHERE子句并将其添加到以下位置来获得所需的功能。声明的结尾:

WHERE

请参见INSERT INTO actions (name, value) values ('bla', 'val1') ON CONFLICT(name) DO UPDATE SET value = excluded.value WHERE value IS NULL; INSERT INTO actions (name, value) values ('bla', 'val2') ON CONFLICT(name) DO UPDATE SET value = excluded.value WHERE value IS NULL;

© www.soinside.com 2019 - 2024. All rights reserved.