Saya telah menemukan beberapa "akan menjadi" solusi untuk klasik "Bagaimana cara menyisipkan catatan baru atau memperbarui jika sudah ada" tetapi saya tidak dapat membuat mereka bekerja di SQLite.
Saya memiliki tabel yang didefinisikan sebagai berikut:
CREATE TABLE Book
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name VARCHAR(60) UNIQUE,
TypeID INTEGER,
Level INTEGER,
Seen INTEGER
Yang ingin saya lakukan adalah menambahkan catatan dengan Nama yang unik. Jika Nama sudah ada, saya ingin memodifikasi bidang.
Adakah yang bisa memberi tahu saya cara melakukan ini?
Jawaban:
Lihat http://sqlite.org/lang_conflict.html .
Anda menginginkan sesuatu seperti:
Perhatikan bahwa bidang apa pun yang tidak ada dalam daftar sisipan akan disetel ke NULL jika baris sudah ada dalam tabel. Inilah sebabnya mengapa ada subselect untuk
ID
kolom: Dalam kasus penggantian pernyataan akan mengaturnya ke NULL dan kemudian ID baru akan dialokasikan.Pendekatan ini juga dapat digunakan jika Anda ingin meninggalkan nilai bidang tertentu sendiri jika baris dalam case pengganti tetapi setel field ke NULL dalam kasus insert.
Misalnya, dengan asumsi Anda ingin pergi
Seen
sendiri:sumber
Level
pendekatan ini tidak dapat diikuti.Anda harus menggunakan
INSERT OR IGNORE
perintah yang diikuti olehUPDATE
perintah: Dalam contoh berikutname
adalah kunci utama:Perintah pertama akan memasukkan catatan. Jika catatan ada, itu akan mengabaikan kesalahan yang disebabkan oleh konflik dengan kunci utama yang ada.
Perintah kedua akan memperbarui catatan (yang sekarang pasti ada)
sumber
Anda perlu menetapkan batasan pada tabel untuk memicu " konflik " yang kemudian Anda selesaikan dengan melakukan penggantian:
Maka Anda dapat mengeluarkan:
"SELECT * FROM data" akan memberi Anda:
Perhatikan bahwa data.id adalah "3" dan bukan "1" karena REPLACE melakukan DELETE dan INSERT, bukan UPDATE. Ini juga berarti bahwa Anda harus memastikan bahwa Anda mendefinisikan semua kolom yang diperlukan atau Anda akan mendapatkan nilai NULL yang tidak terduga.
sumber
Perbarui dulu. Jika jumlah baris yang terpengaruh = 0, maka masukkan. Yang paling mudah dan cocok untuk semua RDBMS .
sumber
Insert or Replace
benar-benar lebih disukai.INSERT OR REPLACE
akan mengganti bidang lain ke nilai default.Jika Anda ingin melestarikan bidang lainnya
atau menggunakan UPSERT (sintaks ditambahkan ke SQLite dengan versi 3.24.0 (2018-06-04))
The
excluded.
awalan sama dengan nilai diVALUES
.sumber
Upsert adalah apa yang Anda inginkan.
UPSERT
sintaks telah ditambahkan ke SQLite dengan versi 3.24.0 (2018-06-04).Berhati-hatilah bahwa pada titik ini kata "UPSERT" yang sebenarnya bukan bagian dari sintaks yang tidak aktif.
Sintaks yang benar adalah
INSERT INTO ... ON CONFLICT(...) DO UPDATE SET...
dan jika Anda melakukan
INSERT INTO SELECT ...
kebutuhan pilih Anda setidaknyaWHERE true
untuk menyelesaikan ambiguitas parser tentang tokenON
dengan sintaks join.Berhati-hatilah bahwa
INSERT OR REPLACE...
akan menghapus catatan sebelum memasukkan yang baru jika harus diganti, yang bisa jadi buruk jika Anda memiliki kaskade kunci asing atau pemicu penghapusan lainnya.sumber
UPSERT
sintaksis.Jika Anda tidak memiliki kunci utama, Anda dapat menyisipkan jika tidak ada, kemudian lakukan pembaruan. Tabel harus mengandung setidaknya satu entri sebelum menggunakan ini.
sumber
Saya yakin Anda menginginkan UPSERT .
"INSERT ATAU REPLACE" tanpa tipu daya tambahan dalam jawaban itu akan mengatur ulang setiap bidang yang tidak Anda tentukan ke NULL atau nilai default lainnya. (Perilaku INSERT ATAU PENGGANTIAN ini tidak seperti UPDATE; ini persis seperti INSERT, karena sebenarnya INSERT; namun jika yang Anda inginkan adalah UPDATE-jika-ada, Anda mungkin menginginkan semantik UPDATE dan akan terkejut dengan hasil yang sebenarnya.)
Tipuan dari implementasi UPSERT yang disarankan pada dasarnya adalah dengan menggunakan INSERT atau REPLACE, tetapi tentukan semua bidang, menggunakan klausa SELECT tertanam untuk mengambil nilai saat ini untuk bidang yang tidak ingin Anda ubah.
sumber
Saya pikir ada baiknya menunjukkan bahwa mungkin ada beberapa perilaku tak terduga di sini jika Anda tidak benar-benar memahami bagaimana PRIMARY KEY dan UNIK berinteraksi.
Sebagai contoh, jika Anda ingin menyisipkan catatan hanya jika bidang NAME saat ini tidak diambil, dan jika itu, Anda ingin pengecualian kendala untuk memberi tahu Anda, maka MASUKKAN ATAU PENGGANTIAN tidak akan melempar dan pengecualian dan sebaliknya akan menyelesaikan kendala UNIK itu sendiri dengan mengganti catatan yang bertentangan (catatan yang ada dengan NAMA yang sama ). Gaspard's menunjukkan ini dengan sangat baik dalam jawabannya di atas.
Jika Anda ingin pengecualian kendala untuk api, Anda harus menggunakan pernyataan INSERT , dan bergantung pada perintah UPDATE terpisah untuk memperbarui catatan setelah Anda tahu nama tidak diambil.
sumber