PostgreSQL INSERT ON CONFLICT UPDATE (upsert) używa wszystkich wykluczonych wartości

142

Kiedy dodajesz wiersz (PostgreSQL> = 9.5) i chcesz, aby możliwe INSERT było dokładnie takie samo, jak możliwe UPDATE, możesz napisać to w ten sposób:

INSERT INTO tablename (id, username, password, level, email) 
                VALUES (1, 'John', 'qwerty', 5, '[email protected]') 
ON CONFLICT (id) DO UPDATE SET 
  id=EXCLUDED.id, username=EXCLUDED.username,
  password=EXCLUDED.password, level=EXCLUDED.level,email=EXCLUDED.email

Czy istnieje krótsza droga? Po prostu powiedzieć: użyj wszystkich wartości EXCLUDE.

W SQLite robiłem:

INSERT OR REPLACE INTO tablename (id, user, password, level, email) 
                        VALUES (1, 'John', 'qwerty', 5, '[email protected]')
Sebastian
źródło
43
Nie jest to prawdziwa odpowiedź, ale możesz użyć nieco krótkiej notacji: INSERT INTO tablename (id, username, password, level, email) VALUES (1, 'John', 'qwerty', 5, '[email protected]') ON CONFLICT (id) DO UPDATE SET (username, password, level, email) = (EXCLUDED.username, EXCLUDED.password, EXCLUDED.level, EXCLUDED.email).Prawie taka sama, ale łatwa do skopiowania / wklejenia / zarządzania listą kolumn
źrebię
Inną opcją jest użycie kolumn jsonb i dzięki temu nie musisz się martwić o kolumny
j będzie

Odpowiedzi:

162

Postgres nie zaimplementował odpowiednika INSERT OR REPLACE. Z ON CONFLICTdokumentacji (moje podkreślenie):

Może to być albo NIC NIE ROBIĆ, albo klauzula DO UPDATE określająca dokładne szczegóły akcji UPDATE, która ma zostać wykonana w przypadku konfliktu.

Chociaż nie daje skrótu do wymiany, ON CONFLICT DO UPDATEma bardziej ogólne zastosowanie, ponieważ pozwala ustawić nowe wartości w oparciu o istniejące dane. Na przykład:

INSERT INTO users (id, level)
VALUES (1, 0)
ON CONFLICT (id) DO UPDATE
SET level = users.level + 1;
Kristján
źródło
3
Uwaga: „przy aktualizacji” nie jest semantycznie identyczne z „scalaniem” standardu SQL, chociaż zwykle można go używać w tych samych miejscach. Miałem przypadek, w którym spodziewałem się, że włączy się „aktualizacja w przypadku konfliktu”, ale dokładny problem we wkładce nie spowodował uruchomienia aktualizacji (która naprawiłaby uszkodzony rekord).
pojo-guy
2
Czy możesz rozwinąć temat „ale dokładny problem we wkładce nie spowodował aktualizacji”?
MrR
@ pojo-guy - chyba nie widziałeś pytania od MrR - czy możesz rozwinąć "ale dokładny problem we wkładce nie spowodował aktualizacji"?
Randall
Gdy spróbujesz użyć wstawiania ... przy aktualizacji w postgresql, wyniki są inne w określonych okolicznościach niż scalanie. Przypadek, na który się natknąłem, był raczej niejasny i konkretny, ale był powtarzalny. Minęło już kilka miesięcy, więc nie mogę teraz dać więcej.
pojo-guy
Może to nie był konflikt, a inny błąd, np. Błąd typu pola?
MrR