我使用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

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


当前回答

解决办法很简单,但不是立竿见影的。 如果你想使用这条指令,你必须对db做一个修改:

ALTER USER user SET search_path to 'name_of_schema';

在这些改变后,“插入”将正常工作。

其他回答

我们可以使用upsert简化查询

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

我正在寻找一个类似的解决方案,试图找到在PostgreSQL和HSQLDB中工作的SQL。(HSQLDB使这变得困难。)以你的例子为基础,这是我在其他地方发现的格式。

sql = "INSERT INTO hundred (name,name_slug,status)"
sql += " ( SELECT " + hundred + ", '" + hundred_slug + "', " + status
sql += " FROM hundred"
sql += " WHERE name = " + hundred + " AND name_slug = '" + hundred_slug + "' AND status = " + status
sql += " HAVING COUNT(*) = 0 );"

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

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

Psycopgs游标类具有rowcount属性。

此只读属性指定最后的行数 execute*()产生的(对于像SELECT这样的DQL语句)或影响的(对于 DML语句,如UPDATE或INSERT)。

因此,您可以先尝试UPDATE,然后仅在rowcount为0时尝试INSERT。

但是根据数据库中的活动级别,您可能会在UPDATE和INSERT之间遇到竞争条件,其中另一个进程可能会在此期间创建该记录。

你可以在Postgres中使用VALUES:

INSERT INTO person (name)
    SELECT name FROM person
    UNION 
    VALUES ('Bob')
    EXCEPT
    SELECT name FROM person;