685 Stimmen

Postgres: INSERT wenn nicht bereits vorhanden

Ich verwende Python, um in eine Postgres-Datenbank zu schreiben:

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

Da aber einige meiner Zeilen identisch sind, erhalte ich folgende Fehlermeldung:

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

Wie kann ich eine SQL-Anweisung "INSERT unless this row already exists" schreiben?

Ich habe gesehen, dass komplexe Aussagen wie diese empfohlen werden:

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

Aber erstens ist dies overkill für was ich brauche, und zweitens, wie kann ich eine von denen als eine einfache Zeichenfolge ausführen?

16voto

Sie können VALUES verwenden, die in Postgres verfügbar sind:

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

10voto

ktr Punkte 626

Ich weiß, dass diese Frage schon eine Weile her ist, aber ich dachte, sie könnte jemandem helfen. Ich denke, der einfachste Weg, dies zu tun ist über einen Auslöser. Z.B.:

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();

Führen Sie diesen Code von einer psql-Eingabeaufforderung aus (oder wie auch immer Sie Abfragen direkt in der Datenbank ausführen möchten). Dann können Sie wie gewohnt von Python aus einfügen. z.B.:

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

Wie @Thomas_Wouters bereits erwähnt hat, nutzt der obige Code die Vorteile von Parametern, anstatt die Zeichenfolge zu verketten.

8voto

Enggar R Hariawan Punkte 369

Können wir die Abfrage mit upsert vereinfachen

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

8voto

Ritesh Jha Punkte 271

Es gibt eine schöne Möglichkeit, bedingte INSERT in PostgreSQL mit WITH-Abfrage zu tun: Zum Beispiel:

WITH a as(
select 
 id 
from 
 schema.table_name 
where 
 column_name = your_identical_column_value
)
INSERT into 
 schema.table_name
(col_name1, col_name2)
SELECT
    (col_name1, col_name2)
WHERE NOT EXISTS (
     SELECT
         id
     FROM
         a
        )
  RETURNING id

4voto

Pavel Francírek Punkte 178

INSERT WHERE NOT EXISTS ist ein guter Ansatz. Und Race Conditions können durch die Transaktion "envelope" vermieden werden:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X