使用多个唯一约束进行Postgres冲突处理

qed*_*ed- 35 postgresql

我想使用insert .. on confict do update ..语法与一个对两列有唯一约束的表.这可能吗?

例如,mytable对col1和col2有独立的唯一约束.

我可以写:

INSERT INTO mytable(col1, col2, col3) values ('A', 'B', 0) ON CONFLICT DO NOTHING;
Run Code Online (Sandbox Code Playgroud)

但是这不起作用:

INSERT INTO mytable(col1, col2, col3) VALUES ('A', 'B', 0) 
ON CONFLICT 
DO UPDATE SET col3 = EXCLUDED.col3 + 1;
Run Code Online (Sandbox Code Playgroud)

错误: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;
Run Code Online (Sandbox Code Playgroud)

错误:没有与ON CONFLICT规范匹配的唯一或排除约束

此语法似乎是针对两列而不是两个约束的单个复合唯一约束而设计的.

如果违反任何唯一约束,有没有办法进行条件更新?这个问题如何在Postgres中关于2列中的一列冲突?暗示但不提供语法.

Vic*_*Vic 32

ON CONFLICT当我们要求时,该子句需要一个唯一的约束DO UPDATE.定义主键时,仅引用列名就足够了; 这是人们倾向于找到的主要例子.

你提到你对col1和col2有'独特的约束',所以我可能认为你的表定义类似于:

CREATE TABLE mytable(       
    col1 varchar UNIQUE,    
    col2 varchar UNIQUE,    
    col3 int
);
Run Code Online (Sandbox Code Playgroud)

但是您的查询引用了复合约束; 而不是单独的约束.修改后的表定义如下:

CREATE TABLE mytable2(  
    col1 varchar UNIQUE,
    col2 varchar UNIQUE,
    col3 int,
    CONSTRAINT ux_col1_col2 UNIQUE (col1,col2)
);
Run Code Online (Sandbox Code Playgroud)

可以使用上面的查询:

INSERT INTO mytable(col1, col2, col3) VALUES ('A', 'B', 0)
ON CONFLICT (col1, col2) 
DO UPDATE SET col3 = EXCLUDED.col3 + 1;
Run Code Online (Sandbox Code Playgroud)

您可以将此唯一约束引用为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;
Run Code Online (Sandbox Code Playgroud)


Nie*_*Wet 9

由于冲突目标不能是两个不同的唯一约束,因此您必须使用模拟更新插入并自行处理冲突。

-- 期望的

INSERT INTO mytable(col1, col2, col3) VALUES ('A', 'B', 0) ON CONFLICT 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 * FROM upsert);
Run Code Online (Sandbox Code Playgroud)

该语句将生成包含 A 或 B 或两者的行,换句话说,满足唯一性 oncol1和唯一性 on 。col2

不幸的是,这个解决方案受到限制,即 A 和 B 之间必须存在某种逻辑链接,否则如果('A', null)插入,然后是(null, B)然后然后,(A, B)您将最终得到两行,均由第三次插入增加:

| col1 | col2 | col3 |
+------+------+------+
|    A | null |    1 |
| null |    B |    1 |
Run Code Online (Sandbox Code Playgroud)