我使用Python写postgres数据库:

sql_string = "INSERT INTO hundred (name,name_slug,status) VALUES ("
sql_string += hundred + ", '" + hundred_slug + "', " + status + ");"
cursor.execute(sql_string)

但由于我的一些行是相同的,我得到以下错误:

psycopg2.IntegrityError: duplicate key value  
  violates unique constraint "hundred_pkey"

我怎么能写一个'插入,除非这行已经存在' SQL语句?

我见过这样的复杂语句:

IF EXISTS (SELECT * FROM invoices WHERE invoiceid = '12345')
UPDATE invoices SET billed = 'TRUE' WHERE invoiceid = '12345'
ELSE
INSERT INTO invoices (invoiceid, billed) VALUES ('12345', 'TRUE')
END IF

但首先,这对我需要的东西来说是不是太过了,其次,我怎么能把它们作为一个简单的字符串来执行呢?


当前回答

我们可以使用upsert简化查询

insert into invoices (invoiceid, billed) 
  values ('12345', 'TRUE') 
  on conflict (invoiceid) do 
    update set billed=EXCLUDED.billed;

其他回答

如果你说你的许多行是相同的,你将结束检查很多次。您可以发送它们,数据库将确定是否使用ON CONFLICT子句插入它,如下所示

  INSERT INTO Hundred (name,name_slug,status) VALUES ("sql_string += hundred  
  +",'" + hundred_slug + "', " + status + ") ON CONFLICT ON CONSTRAINT
  hundred_pkey DO NOTHING;" cursor.execute(sql_string);

我怎么能写一个'插入,除非这行已经存在' SQL语句?

在PostgreSQL中有一个很好的方法来执行有条件的INSERT:

INSERT INTO example_table
    (id, name)
SELECT 1, 'John'
WHERE
    NOT EXISTS (
        SELECT id FROM example_table WHERE id = 1
    );

注意:对于并发写操作,这种方法不是100%可靠的。在NOT EXISTS反半连接中的SELECT和INSERT本身之间有一个非常小的竞争条件。在这种情况下,它可能会失败。

这正是我所面临的问题,我的版本是9.5

我用下面的SQL查询来解决它。

INSERT INTO example_table (id, name)
SELECT 1 AS id, 'John' AS name FROM example_table
WHERE NOT EXISTS(
            SELECT id FROM example_table WHERE id = 1
    )
LIMIT 1;

希望这能帮助那些在>= 9.5版本有同样问题的人。

感谢阅读。

您的列“hundred”似乎被定义为主键,因此必须是唯一的,但事实并非如此。问题不在于你,而在于你的数据。

我建议您插入一个id作为串行类型来处理主键

插入……“不存在的地方”是个好方法。而竞争条件可以通过事务“信封”来避免:

BEGIN;
LOCK TABLE hundred IN SHARE ROW EXCLUSIVE MODE;
INSERT ... ;
COMMIT;