我想使用insert .. on confict do update ..语法与一个对两列有唯一约束的表。这可能吗?
e.g。 mytable对col1和col2有独立的唯一约束。
我可以写:
INSERT INTO mytable(col1, col2, col3) values ('A', 'B', 0) ON CONFLICT DO NOTHING;
然而,这不起作用:
INSERT INTO mytable(col1, col2, col3) VALUES ('A', 'B', 0)
ON CONFLICT
DO UPDATE SET col3 = EXCLUDED.col3 + 1;
ERROR:ON CONFLICT DO UPDATE需要推理规范或约束名称
这也不起作用:
INSERT INTO mytable(col1, col2, col3) VALUES ('A', 'B', 0)
ON CONFLICT (col1, col2)
DO UPDATE SET col3 = EXCLUDED.col3 + 1;
错误:没有与ON CONFLICT规范匹配的唯一或排除约束
这种语法似乎是针对两列的单个复合唯一约束而设计的,而不是两个约束。
如果违反任何一个唯一约束,有没有办法进行条件更新?这个问题How to upsert in Postgres on conflict on one of 2 columns?暗示了它,但没有提供语法。
答案 0 :(得分:25)
ON CONFLICT
子句在我们要求DO UPDATE
时需要一个唯一约束。定义主键时,仅引用列名就足够了;这是人们倾向于找到的主要例子。
您提到您已对col1和col2'分隔了唯一约束,因此我可能会假设您的表定义与此类似:
CREATE TABLE mytable(
col1 varchar UNIQUE,
col2 varchar UNIQUE,
col3 int
);
但您的查询引用了复合约束;而不是单独的约束。修改后的表定义如下:
CREATE TABLE mytable2(
col1 varchar UNIQUE,
col2 varchar UNIQUE,
col3 int,
CONSTRAINT ux_col1_col2 UNIQUE (col1,col2)
);
可以使用上面的查询:
INSERT INTO mytable(col1, col2, col3) VALUES ('A', 'B', 0)
ON CONFLICT (col1, col2)
DO UPDATE SET col3 = EXCLUDED.col3 + 1;
您可以将此唯一约束引用为ON CONFLICT (col1, col2)
或ON CONFLICT ON CONSTRAINT ux_col1_col2
。
但等等,还有......
这个想法是保持一个与之匹配的最新的计数器列 要么是唯一列,要么如果两者都不存在则插入零...
这与你在这里采取的路径不同。 " 匹配任一列"允许在两者上,两者之一或两者之间进行匹配。如果我理解你的意图,只需要一个标签并增加适用记录上的计数器。所以:
CREATE TABLE mytable2(
col1 varchar PRIMARY KEY,
col3 int
);
INSERT INTO mytable2(col1,col3)
SELECT incr_label,0
FROM (VALUES ('A'),('B'),('C')) as increment_list(incr_label)
ON CONFLICT (col1)
DO UPDATE SET col3 = mytable2.col3 + 1
RETURNING col1,col3;
答案 1 :(得分:1)
因为 conflict_target 不能是两个不同的唯一约束,所以您必须使用模拟的 upsert 并自己处理冲突。
<块引用>-- 需要
INSERT INTO mytable(col1, col2, col3) VALUES ('A', 'B', 0) 关于冲突 DO UPDATE SET col3 = EXCLUDED.col3 + 1;
WITH upsert AS (
UPDATE mytable
SET col1 = 'A', col2 = 'B', col3 = col3 + 1
WHERE col1 = 'A' OR col2 = 'B'
RETURNING *
)
INSERT INTO mytable (col1, col2, col3)
SELECT 'A', 'B', 0
WHERE NOT EXISTS (SELECT * FORM upsert);
此语句将导致包含 A 或 B 或两者的行,换句话说,col1
上的唯一性和 col2
上的唯一性得到满足。
不幸的是,此解决方案受到 A 和 B 之间必须存在某种逻辑链接的限制,否则如果插入 ('A', null)
,然后是 (null, B)
,然后是 (A, B)
,您将结束最多两行,都由第三个插入增加:
| col1 | col2 | col3 |
+------+------+------+
| A | null | 1 |
| null | B | 1 |