upsert冲突标签中的where子句

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

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

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
2个回答
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,这不会失败,但这也不会正确分配新值。

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