PostgreSQL INSERT ON CONFLICT UPDATE (upsert) utilizza tutti i valori esclusi


142

Quando stai inviando una riga (PostgreSQL> = 9.5) e vuoi che il possibile INSERT sia esattamente uguale al possibile UPDATE, puoi scriverlo in questo modo:

INSERT INTO tablename (id, username, password, level, email) 
                VALUES (1, 'John', 'qwerty', 5, 'john@mail.com') 
ON CONFLICT (id) DO UPDATE SET 
  id=EXCLUDED.id, username=EXCLUDED.username,
  password=EXCLUDED.password, level=EXCLUDED.level,email=EXCLUDED.email

C'è un modo più breve? Per dire solo: usa tutti i valori EXCLUDE.

In SQLite facevo:

INSERT OR REPLACE INTO tablename (id, user, password, level, email) 
                        VALUES (1, 'John', 'qwerty', 5, 'john@mail.com')

43
Non è una vera risposta, ma puoi usare un po 'di notazione in breve: INSERT INTO tablename (id, username, password, level, email) VALUES (1, 'John', 'qwerty', 5, 'john@mail.com') ON CONFLICT (id) DO UPDATE SET (username, password, level, email) = (EXCLUDED.username, EXCLUDED.password, EXCLUDED.level, EXCLUDED.email).quasi lo stesso, ma facile da copiare / incollare / gestire l'elenco delle colonne
puledro,

Un'altra opzione è quella di utilizzare le colonne jsonb e in questo modo non devi preoccuparti delle colonne
j

Risposte:


162

Postgres non ha implementato un equivalente di INSERT OR REPLACE. Dai ON CONFLICTdocumenti (il mio accento è mio):

Può essere DO NOTHING o una clausola DO UPDATE che specifica i dettagli esatti dell'azione UPDATE da eseguire in caso di conflitto.

Sebbene non ti dia una scorciatoia per la sostituzione, si ON CONFLICT DO UPDATEapplica più in generale, poiché ti consente di impostare nuovi valori in base a dati preesistenti. Per esempio:

INSERT INTO users (id, level)
VALUES (1, 0)
ON CONFLICT (id) DO UPDATE
SET level = users.level + 1;

3
Come avvertimento, "in aggiornamento" non è semanticamente identico alla "unione" dello standard SQL, sebbene di solito possa essere utilizzato negli stessi posti. Ho avuto un caso in cui mi aspettavo l'avvio dell'aggiornamento "in conflitto", ma l'esatto problema nell'inserto non ha causato l'attivazione dell'aggiornamento (che avrebbe riparato il record danneggiato).
pojo-guy

2
Puoi espandere "ma l'esatto problema nell'inserto non ha causato l'aggiornamento"?
MrR

@ pojo-guy - Non credo che tu abbia visto la domanda di MrR - Puoi espandere "ma l'esatto problema nell'inserto non ha causato l'aggiornamento"?
Randall,

Quando si tenta di utilizzare insert ... su update in postgresql, i risultati sono diversi in alcune circostanze specifiche rispetto a un'unione. Il caso in cui mi sono imbattuto era piuttosto oscuro e specifico, ma era ripetibile. Sono passati alcuni mesi, quindi non posso più dare il diritto.
pojo-guy,

Forse non è stato un conflitto ma un altro errore, ad esempio un errore di tipo di campo?
MrR
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.