Saya menggunakan Python untuk menulis ke database postgres:
sql_string = "INSERT INTO hundred (name,name_slug,status) VALUES ("
sql_string += hundred + ", '" + hundred_slug + "', " + status + ");"
cursor.execute(sql_string)
Tetapi karena beberapa baris saya identik, saya mendapatkan kesalahan berikut:
psycopg2.IntegrityError: duplicate key value
violates unique constraint "hundred_pkey"
Bagaimana saya bisa menulis pernyataan SQL 'INSERT kecuali baris ini sudah ada'?
Saya telah melihat pernyataan kompleks seperti ini direkomendasikan:
IF EXISTS (SELECT * FROM invoices WHERE invoiceid = '12345')
UPDATE invoices SET billed = 'TRUE' WHERE invoiceid = '12345'
ELSE
INSERT INTO invoices (invoiceid, billed) VALUES ('12345', 'TRUE')
END IF
Tetapi pertama-tama, apakah ini berlebihan untuk apa yang saya butuhkan, dan kedua, bagaimana saya bisa mengeksekusi salah satu dari mereka sebagai string sederhana?
postgresql
sql-insert
upsert
AP257
sumber
sumber
Jawaban:
Postgres 9.5 (dirilis sejak 2016-01-07) menawarkan perintah "upsert" , juga dikenal sebagai klausa ON CONFLICT ke INSERT :
Ini memecahkan banyak masalah halus yang bisa Anda hadapi ketika menggunakan operasi bersamaan, yang diajukan beberapa jawaban lainnya.
sumber
INSERT INTO distributors (did, dname) VALUES (7, 'Redline GmbH') ON CONFLICT (did) DO NOTHING;
(2) MASUKKAN jika tidak ada yang lain UPDATE -INSERT INTO distributors (did, dname) VALUES (5, 'Gizmo Transglobal'), (6, 'Associated Computing, Inc') ON CONFLICT (did) DO UPDATE SET dname = EXCLUDED.dname;
Contoh-contoh ini dari manual - postgresql.org/docs/9.5/static/sql-insert.htmlAda cara yang baik untuk melakukan INSERT bersyarat di PostgreSQL:
CAVEAT Pendekatan ini tidak 100% andal untuk operasi penulisan bersamaan . Ada kondisi ras yang sangat kecil antara
SELECT
di dalamNOT EXISTS
anti-semi-join danINSERT
itu sendiri. Ini bisa gagal dalam kondisi seperti itu.sumber
RETURNS id
misalnya untuk mendapatkanid
apakah sudah dimasukkan atau belum?RETURNING id
pada dan dari kueri dan itu akan mengembalikan id baris baru atau tidak sama sekali, jika tidak ada baris yang dimasukkan.Salah satu pendekatan akan membuat tabel non-kendala (tidak ada indeks unik) untuk memasukkan semua data Anda ke dalam dan melakukan pilih berbeda dari itu untuk melakukan memasukkan Anda ke dalam seratus tabel Anda.
Jadi level tinggi akan. Saya berasumsi ketiga kolom berbeda dalam contoh saya jadi untuk langkah 3 ubah BUKAN EXIT bergabung dengan hanya bergabung pada kolom unik dalam tabel seratus.
Buat tabel sementara. Lihat dokumen di sini .
Masukkan data ke tabel temp.
Tambahkan indeks ke tabel temp.
Apakah memasukkan tabel utama.
sumber
SELECT name,name_slug,status
atau*
SELECT DISTINCT name, name_slug, status FROM temp_data
?Sayangnya,
PostgreSQL
tidak mendukungMERGE
jugaON DUPLICATE KEY UPDATE
, jadi Anda harus melakukannya dalam dua pernyataan:Anda dapat membungkusnya menjadi fungsi:
dan sebut saja:
sumber
INSERT INTO hundred (name, name_slug, status) SELECT 'Chichester', 'chichester', NULL WHERE 'Chichester' NOT IN (SELECT NAME FROM hundred);
beberapa kali, dan itu tetap memasukkan baris.CREATE TABLE hundred (name TEXT, name_slug TEXT, status INT); INSERT INTO hundred (name, name_slug, status) SELECT 'Chichester', 'chichester', NULL WHERE 'Chichester' NOT IN (SELECT NAME FROM hundred); INSERT INTO hundred (name, name_slug, status) SELECT 'Chichester', 'chichester', NULL WHERE 'Chichester' NOT IN (SELECT NAME FROM hundred); SELECT * FROM hundred
. Ada satu catatan.Anda dapat menggunakan VALUES - tersedia di Postgres:
sumber
Saya tahu pertanyaan ini dari beberapa waktu yang lalu, tetapi berpikir ini mungkin membantu seseorang. Saya pikir cara termudah untuk melakukan ini adalah melalui pemicu. Misalnya:
Jalankan kode ini dari prompt psql (atau bagaimanapun Anda ingin mengeksekusi query langsung pada database). Kemudian Anda dapat memasukkan seperti biasa dari Python. Misalnya:
Perhatikan bahwa seperti yang sudah disebutkan oleh @Thomas_Wouters, kode di atas memanfaatkan parameter daripada menyatukan string.
sumber
Ada cara yang baik untuk melakukan INSERT bersyarat di PostgreSQL menggunakan DENGAN query: Seperti:
sumber
Ini persis masalah yang saya hadapi dan versi saya 9.5
Dan saya menyelesaikannya dengan query SQL di bawah ini.
Semoga itu akan membantu seseorang yang memiliki masalah yang sama dengan versi> = 9.5.
Terima kasih sudah membaca.
sumber
MASUK .. TIDAK ADA pendekatan yang bagus. Dan kondisi lomba dapat dihindari dengan "amplop" transaksi:
sumber
Mudah dengan aturan:
Tetapi gagal dengan bersamaan menulis ...
sumber
Pendekatan dengan sebagian besar upvotes (dari John Doe) entah bagaimana bekerja untuk saya tetapi dalam kasus saya dari yang diharapkan 422 baris saya hanya mendapatkan 180. Saya tidak dapat menemukan sesuatu yang salah dan tidak ada kesalahan sama sekali, jadi saya mencari yang berbeda pendekatan sederhana.
Menggunakan
IF NOT FOUND THEN
setelahSELECT
hanya berfungsi dengan baik untuk saya.(dijelaskan dalam Dokumentasi PostgreSQL )
Contoh dari dokumentasi:
sumber
kelas kursor psycopgs memiliki atribut rowcount .
Jadi, Anda dapat mencoba PEMBARUAN terlebih dahulu dan MASUKKAN hanya jika rowcount adalah 0.
Tetapi tergantung pada tingkat aktivitas dalam basis data Anda, Anda dapat mencapai kondisi balapan antara UPDATE dan INSERT tempat proses lain dapat membuat catatan itu untuk sementara.
sumber
Kolom Anda "ratus" tampaknya didefinisikan sebagai kunci utama dan oleh karena itu harus unik yang tidak demikian. Masalahnya bukan dengan, itu dengan data Anda.
Saya sarankan Anda memasukkan id sebagai tipe serial untuk menangani kunci utama
sumber
Jika Anda mengatakan bahwa banyak baris Anda identik, Anda akan berakhir memeriksa berulang kali. Anda dapat mengirimnya dan database akan menentukan apakah memasukkannya atau tidak dengan klausa ON CONFLICT sebagai berikut
sumber
Saya sedang mencari solusi yang serupa, berusaha menemukan SQL yang berfungsi di PostgreSQL dan juga HSQLDB. (HSQLDB adalah apa yang membuat ini sulit.) Menggunakan contoh Anda sebagai dasar, ini adalah format yang saya temukan di tempat lain.
sumber
Berikut adalah fungsi python generik yang memberikan nama tab, kolom, dan nilai, menghasilkan ekuivalen upsert untuk postgresql.
impor json
sumber
Solusinya sederhana, tetapi tidak dengan segera.
Jika Anda ingin menggunakan instruksi ini, Anda harus melakukan satu perubahan pada db:
setelah perubahan ini "INSERT" akan berfungsi dengan benar.
sumber