INSERT与SELECT NOT EXISTS错误重复键

时间:2015-02-08 09:55:53

标签: postgresql sql-insert

怎么会发生这种情况?

IntegrityError: (IntegrityError) duplicate key value violates unique constraint "r_u_pkey"  
DETAIL:  Key (r_id, u_id)=(2660, 10182) already exists.  
 'INSERT INTO r_u(r_id, u_id) SELECT %s, %s WHERE NOT EXISTS (
     SELECT 1 FROM r_u WHERE r_id = %s AND u_id = %s
 )' (2660, 10182, 2660, 10182)

(r_id, u_id)上有主键:

CREATE TABLE r_u  
(  
  r_id integer NOT NULL,  
  u_id integer NOT NULL,  
  CONSTRAINT r_u_pkey PRIMARY KEY (r_id, u_id)  
)  

服务器是Postgres 9.3.5并且连接已自动提交。

2 个答案:

答案 0 :(得分:1)

好吧,我找到了理由和解决方案。 INSERT SELECT不是原子的。在autocommit模式下,必须在事务中使用显式锁定:

BEGIN; LOCK TABLE r_u IN SHARE ROW EXCLUSIVE MODE; INSERT INTO r_u(r_id, u_id) SELECT %s, %s WHERE NOT EXISTS ( SELECT 1 FROM r_u WHERE r_id = %s AND u_id = %s ) COMMIT;

来源:http://www.the-art-of-web.com/sql/upsert/

答案 1 :(得分:0)

如果true元组不存在,则内部查询会为表格中的每一行返回2660, 10182 。如果表格中有多行,您就会收到上述错误。

相反,更简洁的方法可能是使用except运算符:

INSERT INTO r_u(r_id, u_id) 
SELECT %s, %s 
FROM   r_u 
EXCEPT
SELECT r_id, u_id
FROM   r_u