Ich habe zwei Spalten in der Tabelle col1
, col2
beide sind eindeutig indiziert (col1 ist eindeutig und col2 auch).
Ich muss beim Einfügen in diese Tabelle die ON CONFLICT
Syntax verwenden und andere Spalten aktualisieren, aber ich kann nicht beide Spalten in conflict_target
Klausel verwenden.
Es klappt:
INSERT INTO table
...
ON CONFLICT ( col1 )
DO UPDATE
SET
-- update needed columns here
Aber wie geht das für mehrere Spalten?
...
ON CONFLICT ( col1, col2 )
DO UPDATE
SET
....
postgresql
upsert
postgresql-9.5
Oto Shavadze
quelle
quelle
Antworten:
Eine Beispieltabelle und Daten
Das Problem reproduzieren
Nennen wir das Q1. Das Ergebnis ist
Was die Dokumentation sagt
Dies erweckt den Eindruck, dass die folgende Abfrage funktionieren sollte, jedoch nicht, da tatsächlich ein eindeutiger Index für col1 und col2 erforderlich wäre. Ein solcher Index würde jedoch nicht garantieren, dass col1 und col2 einzeln eindeutig sind, was eine der Anforderungen des OP ist.
Nennen wir diese Abfrage Q2 (dies schlägt mit einem Syntaxfehler fehl).
Warum?
Postgresql verhält sich so, weil nicht genau definiert ist, was passieren soll, wenn ein Konflikt in der zweiten Spalte auftritt. Es gibt verschiedene Möglichkeiten. Sollte postgresql beispielsweise in der obigen Q1-Abfrage aktualisiert werden,
col1
wenn ein Konflikt bestehtcol2
? Aber was ist, wenn das zu einem weiteren Konflikt führtcol1
? Wie soll postgresql damit umgehen?Eine Lösung
Eine Lösung besteht darin, ON CONFLICT mit altmodischem UPSERT zu kombinieren .
Sie müssten die Logik dieser gespeicherten Funktion so ändern, dass die Spalten genau so aktualisiert werden, wie Sie es möchten. Rufe es wie auf
quelle
ON CONFLICT
erfordert einen eindeutigen Index * für die Konflikterkennung. Sie müssen also nur einen eindeutigen Index für beide Spalten erstellen:* Zusätzlich zu eindeutigen Indizes können Sie auch Ausschlussbeschränkungen verwenden . Diese sind etwas allgemeiner als eindeutige Einschränkungen. Angenommen, Ihre Tabelle enthält Spalten für
id
undvalid_time
(undvalid_time
ist atsrange
), und Sie möchten doppelteid
s zulassen , jedoch nicht für überlappende Zeiträume. Eine eindeutige Einschränkung hilft Ihnen nicht weiter, aber mit einer Ausschlussbeschränkung können Sie sagen: "Neue Datensätze ausschließen, wenn sieid
einem alten entsprechenid
und sich auchvalid_time
überlappenvalid_time
."quelle
ON CONFLICT
?on conflict
Befehl. Der Fehler ist nur "Spalte my_index_name existiert nicht".In der heutigen Zeit ist (scheint) unmöglich. Weder die letzte Version der
ON CONFLICT
Syntax erlaubt es, die Klausel zu wiederholen, noch ist mit CTE möglich: Es ist nicht möglich, das INSERT von ON CONFLICT zu durchbrechen, um weitere Konfliktziele hinzuzufügen.quelle
Wenn Sie Postgres 9.5 verwenden, können Sie den EXCLUDED-Bereich verwenden.
Beispiel aus den Neuerungen in PostgreSQL 9.5 :
quelle
ODER UND
quelle
Ein bisschen hacky, aber ich habe das gelöst, indem ich die beiden Werte von col1 und col2 zu einer neuen Spalte, col3 (ähnlich einem Index der beiden), verkettet und damit verglichen habe. Dies funktioniert nur, wenn Sie es benötigen, um sowohl mit col1 als auch mit col2 übereinzustimmen.
Wobei col3 = die Verkettung der Werte von col1 und col2 ist.
quelle
on conflict
.Vlad hatte die richtige Idee.
Zuerst müssen Sie eine eindeutige Tabelleneinschränkung für die Spalten erstellen.
col1, col2
Anschließend können Sie Folgendes tun:quelle
Sie können normalerweise (ich würde denken) eine Anweisung mit nur einer generieren
on conflict
, die die einzige Einschränkung angibt, die für das Objekt, das Sie einfügen, relevant ist.Denn normalerweise ist jeweils nur eine Einschränkung die "relevante". (Wenn viele, dann frage ich mich, ob etwas seltsam / seltsam gestaltet ist, hmm.)
Beispiel:
(Lizenz: Nicht CC0, nur CC-By)
Und:
Die
on conflict
Klausel wird dynamisch generiert, je nachdem, was ich versuche. Wenn ich eine Benachrichtigungseinstellung für eine Seite einfüge, kann es zu einem eindeutigen Konflikt mit dersite_id, people_id, page_id
Einschränkung kommen. Und wenn ich Benachrichtigungseinstellungen für eine Kategorie konfiguriere, weiß ich stattdessen, dass die Einschränkung, die verletzt werden kann, istsite_id, people_id, category_id
.Also ich kann, und ziemlich wahrscheinlich auch Sie, in Ihrem Fall ?, erzeugen die richtige
on conflict (... columns )
, weil ich weiß , was ich will tun, und dann weiß ich einzelne der vielen einzigartigen Zwänge , die, ist derjenige, der verletzt bekommen.quelle
ON CONFLICT ist eine sehr ungeschickte Lösung
funktioniert mit Oracle, Postgres und allen anderen Datenbanken
quelle