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?

3voto

Mit Regeln ist das einfach:

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

Aber es scheitert bei gleichzeitigem Schreiben ...

1voto

Boodoo Punkte 25

Ihre Spalte "hundert" scheint als Primärschlüssel definiert zu sein und muss daher eindeutig sein, was nicht der Fall ist. Das Problem liegt nicht bei, sondern bei Ihren Daten.

Ich schlage vor, dass Sie eine id als seriellen Typ einfügen, um den Primärschlüssel zu handhaben

1voto

opena Punkte 9

Wenn Sie sagen, dass viele Ihrer Zeilen identisch sind, werden Sie viele Male überprüfen. Sie können sie senden, und die Datenbank bestimmt, ob sie mit der ON CONFLICT-Klausel wie folgt eingefügt wird oder nicht

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

1voto

Christoph Lösch Punkte 499

Der Ansatz mit den meisten Bewertungen (von John Doe) funktioniert irgendwie für mich, aber in meinem Fall erhalte ich von den erwarteten 422 Zeilen nur 180. Ich konnte nichts Falsches finden und es gibt überhaupt keine Fehler, also habe ich nach einem anderen einfachen Ansatz gesucht.

Verwendung von IF NOT FOUND THEN nach einer SELECT funktioniert für mich einfach perfekt.

(beschrieben in PostgreSQL-Dokumentation )

Beispiel aus der Dokumentation:

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

1voto

johnbaum Punkte 666

Psycopgs Cursor-Klasse hat das Attribut Zeilenzahl .

Dieses schreibgeschützte Attribut gibt die Anzahl der Zeilen an, die der letzte execute*() erzeugt (für DQL-Anweisungen wie SELECT) oder beeinflusst hat (für DML-Anweisungen wie UPDATE oder INSERT).

Sie könnten also zuerst UPDATE versuchen und erst dann INSERT, wenn die Zeilenzahl 0 ist.

Je nach Aktivitätsniveau in Ihrer Datenbank kann es jedoch zu einem Wettlauf zwischen UPDATE und INSERT kommen, bei dem ein anderer Prozess den Datensatz in der Zwischenzeit erstellen kann.

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