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

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


当前回答

我正在寻找一个类似的解决方案,试图找到在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 );"

其他回答

有规则很简单:

CREATE RULE file_insert_defer AS ON INSERT TO file
WHERE (EXISTS ( SELECT * FROM file WHERE file.id = new.id)) DO INSTEAD NOTHING

但是并发写失败了…

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

ALTER USER user SET search_path to 'name_of_schema';

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

获得最多赞的方法(来自John Doe)在某种程度上对我有用,但在我的情况下,从预期的422行中,我只得到180行。 我找不到任何错误,根本没有错误,所以我寻找一个不同的简单的方法。

在SELECT之后使用IF NOT FOUND THEN对我来说是完美的。

(在PostgreSQL文档中描述)

来自文档的例子:

SELECT * INTO myrec FROM emp WHERE empname = myname;
IF NOT FOUND THEN
  RAISE EXCEPTION 'employee % not found', myname;
END IF;

我知道这个问题是很久以前提出的,但我想这可能会对一些人有所帮助。我认为最简单的方法就是触发。例如:

Create Function ignore_dups() Returns Trigger
As $$
Begin
    If Exists (
        Select
            *
        From
            hundred h
        Where
            -- Assuming all three fields are primary key
            h.name = NEW.name
            And h.hundred_slug = NEW.hundred_slug
            And h.status = NEW.status
    ) Then
        Return NULL;
    End If;
    Return NEW;
End;
$$ Language plpgsql;

Create Trigger ignore_dups
    Before Insert On hundred
    For Each Row
    Execute Procedure ignore_dups();

从psql提示符(或者您喜欢的直接在数据库上执行查询的方式)执行这段代码。然后你可以像往常一样从Python中插入。例如:

sql = "Insert Into hundreds (name, name_slug, status) Values (%s, %s, %s)"
cursor.execute(sql, (hundred, hundred_slug, status))

注意,正如@Thomas_Wouters已经提到的,上面的代码利用了参数,而不是连接字符串。

一种方法是创建一个不受约束(没有唯一索引)的表,将所有数据插入其中,并执行与插入到百位表不同的选择。

所以高水平。我假设在我的示例中所有三个列都是不同的,因此对于step3,将NOT EXITS连接更改为只连接100表中唯一的列。

Create temporary table. See docs here. CREATE TEMPORARY TABLE temp_data(name, name_slug, status); INSERT Data into temp table. INSERT INTO temp_data(name, name_slug, status); Add any indexes to the temp table. Do main table insert. INSERT INTO hundred(name, name_slug, status) SELECT DISTINCT name, name_slug, status FROM hundred WHERE NOT EXISTS ( SELECT 'X' FROM temp_data WHERE temp_data.name = hundred.name AND temp_data.name_slug = hundred.name_slug AND temp_data.status = status );