INSERT
hanya akan menyisipkan semua baris dan tidak ada spesial akan terjadi, kecuali Anda memiliki semacam batasan melarang nilai duplikat / tumpang tindih (PRIMARY KEY
, UNIQUE
, CHECK
atau EXCLUDE
kendala) - yang tidak Anda sebutkan dalam pertanyaan Anda. Tapi itulah yang mungkin Anda khawatirkan.
Dengan asumsi UNIQUE
atau batasan PK pada (col1,col2)
, Anda berurusan dengan buku teks UPSERT
situasi. Banyak pertanyaan dan jawaban terkait dapat ditemukan di sini.
Umumnya, jika ada batasan dilanggar, pengecualian muncul yang (kecuali terjebak dalam subtransaksi seperti yang mungkin dalam bahasa sisi server prosedural seperti plpgsql) akan memutar kembali tidak hanya pernyataan, tetapi seluruh transaksi .
Tanpa penulisan bersamaan
Yaitu:Tidak ada transaksi lain yang akan mencoba menulis ke tabel yang sama secara bersamaan.
-
Kecualikan baris yang sudah ada di tabel dengan
WHERE NOT EXISTS ...
atau teknik lain yang berlaku: -
Pilih baris yang tidak ada di tabel lain
-
Dan jangan lupa untuk menghapus duplikat di dalam set yang dimasukkan juga, yang tidak dikecualikan oleh semi-anti-join
WHERE NOT EXISTS ...
Salah satu teknik untuk menangani keduanya sekaligus adalah EXCEPT
:
INSERT INTO tbl (col1, col2)
VALUES
(text 'v1', text 'v2') -- explicit type cast may be needed in 1st row
, ('v3', 'v4')
, ('v3', 'v4') -- beware of dupes in source
EXCEPT SELECT col1, col2 FROM tbl;
EXCEPT
tanpa kata kunci ALL
melipat baris duplikat di sumber. Jika Anda tahu tidak ada penipuan, atau Anda tidak ingin melipat duplikat secara diam-diam, gunakan EXCEPT ALL
(atau salah satu teknik lainnya). Lihat:
- Menggunakan klausa KECUALI di PostgreSQL
Umumnya, jika tabel target besar , WHERE NOT EXISTS
dalam kombinasi dengan DISTINCT
pada sumbernya mungkin akan lebih cepat:
INSERT INTO tbl (col1, col2)
SELECT *
FROM (
SELECT DISTINCT *
FROM (
VALUES
(text 'v1', text'v2')
, ('v3', 'v4')
, ('v3', 'v4') -- dupes in source
) t(c1, c2)
) t
WHERE NOT EXISTS (
SELECT FROM tbl
WHERE col1 = t.c1 AND col2 = t.c2
);
Jika ada banyak penipuan, ada baiknya melipatnya di sumbernya terlebih dahulu. Jika tidak, gunakan satu subkueri lebih sedikit.
Terkait:
- Pilih baris yang tidak ada di tabel lain
Dengan penulisan bersamaan
Gunakan Postgres UPSERT
implementasi INSERT ... ON CONFLICT ...
di Postgres 9.5 atau lebih baru:
INSERT INTO tbl (col1,col2)
SELECT DISTINCT * -- still can't insert the same row more than once
FROM (
VALUES
(text 'v1', text 'v2')
, ('v3','v4')
, ('v3','v4') -- you still need to fold dupes in source!
) t(c1, c2)
ON CONFLICT DO NOTHING; -- ignores rows with *any* conflict!
Bacaan lebih lanjut:
- Bagaimana cara menggunakan RETURNING dengan ON CONFLICT di PostgreSQL?
- Bagaimana cara menyisipkan baris yang berisi kunci asing?
Dokumentasi:
- Panduan
- Halaman komit
- Halaman Wiki Postgres
Jawaban referensi Craig untuk UPSERT
masalah:
- Bagaimana cara UPSERT (MERGE, INSERT ... ON DUPLICATE UPDATE) di PostgreSQL?