INSERT PostgreSQL PADA PEMBARUAN KONFLIK (upsert) menggunakan semua nilai yang dikecualikan

142

Ketika Anda memasang baris (PostgreSQL> = 9.5), dan Anda ingin INSERT yang mungkin persis sama dengan UPDATE yang mungkin, Anda dapat menulisnya seperti ini:

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

Apakah ada cara yang lebih pendek? Untuk sekadar mengatakan: gunakan semua nilai EXCLUDE.

Dalam SQLite saya biasa melakukan:

INSERT OR REPLACE INTO tablename (id, user, password, level, email) 
                        VALUES (1, 'John', 'qwerty', 5, '[email protected]')
Sebastian
sumber
43
Bukan jawaban yang sebenarnya tetapi Anda dapat menggunakan notasi yang sebentar lagi: 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).Hampir sama, tetapi mudah untuk menyalin / menempel / mengelola daftar kolom
foal
Pilihan lain adalah menggunakan kolom jsonb dan dengan begitu Anda tidak perlu khawatir tentang kolom
j akan

Jawaban:

162

Postgres belum menerapkan yang setara dengan INSERT OR REPLACE. Dari ON CONFLICTdokumen (penekanan pada saya):

Ini bisa berupa DO NOTHING, atau klausa DO UPDATE yang menentukan detail pasti dari tindakan UPDATE yang akan dilakukan jika terjadi konflik.

Meskipun tidak memberi Anda singkatan untuk penggantian, ON CONFLICT DO UPDATEberlaku lebih umum, karena memungkinkan Anda menetapkan nilai baru berdasarkan data yang sudah ada sebelumnya. Sebagai contoh:

INSERT INTO users (id, level)
VALUES (1, 0)
ON CONFLICT (id) DO UPDATE
SET level = users.level + 1;
Kristjan
sumber
3
Sebagai kata peringatan, "pada pembaruan" tidak semantik identik dengan "gabungan" dari standar SQL, meskipun biasanya dapat digunakan di tempat yang sama. Saya memiliki kasus di mana saya mengharapkan "pada pembaruan konflik" untuk memulai, tetapi masalah yang tepat dalam menyisipkan tidak menyebabkan pembaruan (yang akan memperbaiki catatan yang rusak) untuk menyala.
pojo-guy
2
Bisakah Anda memperluas "tetapi masalah yang sebenarnya dalam menyisipkan tidak menyebabkan pembaruan"?
MrR
@ pojo-guy - Saya tidak berpikir Anda melihat pertanyaan dari MrR - Dapatkah Anda memperluas "tetapi masalah yang sebenarnya dalam menyisipkan tidak menyebabkan pembaruan"?
Randall
Ketika Anda mencoba menggunakan insert ... pada pembaruan di postgresql, hasilnya berbeda dalam beberapa keadaan tertentu daripada gabungan. Kasing yang saya temui agak tidak jelas dan spesifik, tetapi bisa diulang. Sudah beberapa bulan, jadi saya tidak bisa memberikan yang sekarang.
pojo-guy
Mungkin itu bukan konflik tetapi kesalahan lain misalnya kesalahan tipe bidang?
MrR