Beberapa server SQL memiliki fitur di mana INSERT
dilewati jika akan melanggar batasan kunci primer / unik. Sebagai contoh, MySQL memiliki INSERT IGNORE
.
Apa cara terbaik untuk meniru INSERT IGNORE
dan ON DUPLICATE KEY UPDATE
dengan PostgreSQL?
database
postgresql
rules
gpilotino
sumber
sumber
ON DUPLICATE KEY UPDATE
pada PgSQL 9.5 masih agak tidak mungkin, karena PgSQL yangON CLAUSE
setara mengharuskan Anda untuk memberikan nama kendala, sementara MySQL dapat menangkap kendala apa pun tanpa perlu mendefinisikannya. Ini mencegah saya dari "meniru" fitur ini tanpa menulis ulang pertanyaan.Jawaban:
Coba lakukan PEMBARUAN. Jika tidak mengubah baris apa pun yang berarti tidak ada, maka lakukan penyisipan. Jelas, Anda melakukan ini di dalam suatu transaksi.
Anda tentu saja dapat membungkus ini dalam suatu fungsi jika Anda tidak ingin meletakkan kode tambahan di sisi klien. Anda juga memerlukan perulangan untuk kondisi balapan yang sangat langka dalam pemikiran itu.
Ada contohnya dalam dokumentasi ini: http://www.postgresql.org/docs/9.3/static/plpgsql-control-structures.html , contoh 40-2 tepat di bagian bawah.
Itu biasanya cara termudah. Anda dapat melakukan beberapa sihir dengan aturan, tetapi kemungkinannya akan jauh lebih berantakan. Saya akan merekomendasikan pendekatan wrap-in-function lebih dari itu setiap hari.
Ini berfungsi untuk satu baris, atau beberapa baris, nilai. Jika Anda berurusan dengan sejumlah besar baris, misalnya dari subquery, Anda sebaiknya membaginya menjadi dua pertanyaan, satu untuk INSERT dan satu untuk UPDATE (sebagai gabungan / subseleksi yang tepat tentunya - tidak perlu menulis utama Anda filter dua kali)
sumber
INSERT ... ON CONFLICT DO NOTHING;
. Lihat juga jawab stackoverflow.com/a/34639631/2091700 .MERGE
adalah bukan suatu yang aman upsert concurrency, kecuali jika Anda mengambilLOCK TABLE
pertama. Orang menggunakannya seperti itu, tetapi itu salah.Dengan PostgreSQL 9.5, ini sekarang fungsionalitas asli (seperti yang telah dimiliki MySQL selama beberapa tahun):
...
sumber
Sunting: jika Anda melewatkan jawaban warren , PG9.5 sekarang memiliki ini secara asli; saatnya untuk meningkatkan!
Membangun berdasarkan jawaban Bill Karwin, untuk menjabarkan seperti apa pendekatan berbasis aturan (transfer dari skema lain dalam DB yang sama, dan dengan kunci primer multi-kolom):
Catatan: Aturan ini berlaku untuk semua
INSERT
operasi sampai aturan dibatalkan, jadi tidak cukup ad hoc.sumber
another_schema.my_table
berisi duplikat sesuai dengan kendalamy_table
?INSERT INTO "my_table" SELECT DISTINCT ON (pk_col_1, pk_col_2) * FROM the_tmp_table;
DELETE FROM my_table WHERE ctid IN (SELECT ctid FROM (SELECT ctid,ROW_NUMBER() OVER (PARTITION BY pk_col_1,pk_col_2) AS rn FROM my_table) AS dups WHERE dups.rn > 1);
Bagi Anda yang memiliki Postgres 9.5 atau lebih tinggi, sintaks ON ON CONFLICT DO NOTHING seharusnya berfungsi:
Bagi kita yang memiliki versi sebelumnya, hak bergabung ini akan berfungsi sebagai gantinya:
sumber
Unique violation: 7 ERROR: duplicate key value violates unique constraint
ketikatarget_table
baris lain dimasukkan ke dalamnya ketika query ini dieksekusi, jika kunci mereka, memang, saling menduplikasi. Saya percaya bahwa menguncitarget_table
akan membantu, tetapi konkurensi jelas akan menderita.ON CONFLICT (field_one) DO NOTHING
adalah bagian terbaik dari jawabannya.Untuk mendapatkan logika abaikan sisipan Anda dapat melakukan sesuatu seperti di bawah ini. Saya menemukan hanya menyisipkan dari pernyataan pilih dari nilai literal yang paling berhasil, maka Anda dapat menutupi kunci duplikat dengan klausa TIDAK ADA. Untuk mendapatkan pembaruan pada logika duplikat saya curiga loop pl / pgsql akan diperlukan.
sumber
sumber
Sepertinya PostgreSQL mendukung objek skema yang disebut aturan .
http://www.postgresql.org/docs/current/static/rules-update.html
Anda bisa membuat aturan
ON INSERT
untuk tabel tertentu, membuatnyaNOTHING
jika baris ada dengan nilai kunci utama yang diberikan, atau membuatnya melakukanUPDATE
alih - alihINSERT
jika baris ada dengan nilai kunci utama yang diberikan.Saya belum mencoba ini sendiri, jadi saya tidak dapat berbicara dari pengalaman atau memberikan contoh.
sumber
Seperti @hanmari disebutkan dalam komentarnya. ketika memasukkan ke dalam tabel postgres, konflik on (..) do nothing adalah kode terbaik untuk digunakan untuk tidak memasukkan data duplikat .:
Baris kode ON CONFLICT akan memungkinkan pernyataan insert tetap memasukkan baris data. Kode kueri dan nilai adalah contoh tanggal yang dimasukkan dari Excel ke tabel postgres db. Saya memiliki kendala yang ditambahkan ke tabel postgres yang saya gunakan untuk memastikan bidang ID unik. Alih-alih menjalankan penghapusan pada baris data yang sama, saya menambahkan baris kode sql yang menomori ulang kolom ID mulai dari 1. Contoh:
Jika data saya memiliki bidang ID, saya tidak menggunakan ini sebagai ID utama / ID seri, saya membuat kolom ID dan saya mengaturnya ke serial. Saya harap informasi ini bermanfaat bagi semua orang. * Saya tidak memiliki gelar sarjana dalam pengembangan / pengkodean perangkat lunak. Semua yang saya tahu dalam coding, saya belajar sendiri.
sumber
Solusi ini menghindari penggunaan aturan:
tetapi memiliki kekurangan kinerja (lihat PostgreSQL.org ):
sumber
Secara massal, Anda selalu dapat menghapus baris sebelum menyisipkan. Penghapusan baris yang tidak ada tidak menyebabkan kesalahan, jadi tidak dilewati dengan aman.
sumber
DEFERRABLE INITIALLY DEFERRED
bendera.Untuk skrip impor data, untuk mengganti "JIKA TIDAK ADA", dengan cara tertentu, ada formulasi yang agak canggung yang tetap bekerja:
sumber