SQLite memiliki klausa ekstensi SQL non-standar yang disebut ON CONFLICT
yang memungkinkan kita untuk menentukan bagaimana menangani konflik kendala.
Secara khusus, klausa berlaku untuk UNIQUE
, NOT NULL
, CHECK
, dan PRIMARY KEY
kendala.
Artikel ini memberikan contoh bagaimana klausa ini dapat digunakan untuk menentukan cara menangani konflik batasan kunci utama.
Dengan "konflik kendala kunci utama", maksud saya ketika Anda mencoba memasukkan nilai duplikat ke dalam kolom kunci utama. Secara default, ketika Anda mencoba melakukan ini, operasi akan dibatalkan dan SQLite akan mengembalikan kesalahan.
Tetapi Anda dapat menggunakan ON CONFLICT
klausa untuk mengubah cara SQLite menangani situasi ini.
Salah satu opsi adalah menggunakan klausa ini di CREATE TABLE
pernyataan saat membuat tabel. Melakukannya akan menentukan bagaimana semua INSERT
operasi diperlakukan.
Pilihan lainnya adalah menggunakan klausa pada INSERT
pernyataan setiap kali Anda mencoba memasukkan data ke dalam tabel. Ini memungkinkan Anda untuk memanfaatkan klausa bahkan ketika tabel tidak dibuat dengannya. Saat Anda menggunakan opsi ini, sintaksnya berbeda; Anda menggunakan OR
bukannya ON CONFLICT
.
Contoh di halaman ini menggunakan opsi kedua – saya membuat tabel tanpa ON CONFLICT
klausa, dan saya malah menentukan OR
pada INSERT
pernyataan.
Tabel Contoh
Mari buat tabel sederhana dan tambahkan satu baris.
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName,
Price
);
INSERT INTO Products VALUES (1, 'Hammer', 8.00);
SELECT * FROM Products;
Hasil:
ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0
Saat ini kami memiliki satu baris, dengan ProductId dari 1 .
Sekarang kita dapat menjalankan berbagai skenario memasukkan data ke dalam tabel yang melanggar batasan kunci utama.
Contoh 1 – Abort (Perilaku Default)
Seperti yang disebutkan, perilaku default untuk SQLite adalah membatalkan INSERT
operasi dan mengembalikan kesalahan.
INSERT INTO Products VALUES (1, 'Wrench', 12.50);
Hasil:
Error: UNIQUE constraint failed: Products.ProductId
Kesalahan dikembalikan dan tidak ada yang dimasukkan.
Ini sama dengan menggunakan OR ABORT
pilihan.
INSERT OR ABORT INTO Products VALUES (1, 'Wrench', 12.50);
Hasil:
Error: UNIQUE constraint failed: Products.ProductId
Kami dapat memverifikasi bahwa tidak ada yang dimasukkan dengan menjalankan SELECT
pernyataan terhadap meja.
SELECT * FROM Products;
Hasil:
ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0
Kita dapat melihat bahwa tabel hanya berisi baris asli.
Contoh 2 – Abaikan
Salah satu alternatifnya adalah membuat SQLite mengabaikan baris yang menyinggung. Dengan kata lain, ia akan melewati baris dan melanjutkan pemrosesan baris berikutnya.
Untuk melakukannya dalam INSERT
. Anda pernyataan, gunakan OR IGNORE
.
Efeknya adalah INSERT
operasi berhasil, tetapi tanpa baris yang melanggar batasan kunci utama.
INSERT OR IGNORE INTO Products VALUES
(1, 'Hammer', 12.00),
(2, 'Nails', 2.50),
(3, 'Saw', 10.50),
(1, 'Wrench', 22.50),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products;
Hasil:
ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0 2 Nails 2.5 3 Saw 10.5 5 Chisel 23.0 6 Bandage 120.0
Dalam hal ini saya mencoba menyisipkan dua baris baru dengan ID yang sudah ada di tabel, sehingga kedua baris tersebut dilewati.
Contoh 3 – Ganti
Pilihan lain yang Anda miliki adalah mengganti baris asli dengan baris baru.
Dengan kata lain, Anda akan menimpa data yang ada dengan data baru Anda.
Untuk melakukannya, gunakan OR REPLACE
.
INSERT OR REPLACE INTO Products VALUES
(1, 'Hammer', 12.00),
(2, 'Nails', 2.50),
(3, 'Saw', 10.50),
(1, 'Wrench', 22.50),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products;
Hasil:
ProductId ProductName Price ---------- ----------- ---------- 1 Wrench 22.5 2 Nails 2.5 3 Saw 10.5 5 Chisel 23.0 6 Bandage 120.0
Dalam hal ini sebagian besar baris adalah sama, sehingga berisi data yang sama setelah INSERT
operasi. Namun, kita dapat melihat bahwa baris pertama telah diperbarui untuk menggunakan nilai dalam INSERT
saya penyataan.
Kita juga dapat melihat bahwa itu menggunakan kumpulan nilai kedua (melihat dua berbagi ProductId yang sama ).
Jadi efeknya seperti UPDATE
pernyataan dan INSERT
pernyataan digabungkan.
Contoh 4 – Kembalikan
Pilihan lain adalah dengan menggunakan ROLLBACK
pilihan.
Ini membatalkan pernyataan SQL saat ini dengan kesalahan SQLITE_CONSTRAINT dan mengembalikan transaksi saat ini. Jika tidak ada transaksi yang aktif (selain transaksi tersirat yang dibuat pada setiap perintah) maka cara kerjanya sama dengan ABORT
algoritma.
Membayar untuk memperhatikan bagaimana opsi ini bekerja. Berikut adalah contoh yang menggunakan beberapa INSERT OR ROLLBACK
pernyataan dalam suatu transaksi.
DELETE FROM Products;
BEGIN TRANSACTION;
INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 8.00);
INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50);
INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50);
INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50);
INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00);
INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);
COMMIT;
SELECT * FROM Products;
Inilah output lengkap dari terminal saya ketika saya menjalankan ini:
sqlite> BEGIN TRANSACTION; sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 8.00); sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50); sqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50); sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50); Error: UNIQUE constraint failed: Products.ProductId sqlite> INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00); sqlite> INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00); sqlite> COMMIT; Error: cannot commit - no transaction is active sqlite> sqlite> SELECT * FROM Products; ProductId ProductName Price ---------- ----------- ---------- 5 Chisel 23.0 6 Bandage 120.0 sqlite>
Pada dasarnya yang terjadi di sini adalah, telah sampai pada pelanggaran batasan, kemudian membatalkan transaksi. Kemudian dua baris berikutnya diproses dan kemudian COMMIT
kata kunci ditemukan. Saat itu, transaksi telah dibatalkan dan kami mendapatkan kesalahan lain yang memberi tahu kami bahwa tidak ada transaksi yang aktif.
Inilah yang terjadi jika saya menghapusnya dari transaksi.
DELETE FROM Products;
INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 8.00);
INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50);
INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50);
INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50);
INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00);
INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);
SELECT * FROM Products;
Inilah output lengkap dari terminal saya ketika saya menjalankan ini:
sqlite> DELETE FROM Products; sqlite> sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 8.00); sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50); sqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50); sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50); Error: UNIQUE constraint failed: Products.ProductId sqlite> INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00); sqlite> INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00); sqlite> sqlite> SELECT * FROM Products; ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0 2 Nails 2.5 3 Saw 10.5 5 Chisel 23.0 6 Bandage 120.0 sqlite>
Dalam hal ini, ini berfungsi seperti ABORT
.
Untuk mendemonstrasikan ini, berikut pernyataan yang sama menggunakan ABORT
bukannya ROLLBACK
.
DELETE FROM Products;
INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 8.00);
INSERT OR ABORT INTO Products VALUES (2, 'Nails', 2.50);
INSERT OR ABORT INTO Products VALUES (3, 'Saw', 10.50);
INSERT OR ABORT INTO Products VALUES (1, 'Wrench', 22.50);
INSERT OR ABORT INTO Products VALUES (5, 'Chisel', 23.00);
INSERT OR ABORT INTO Products VALUES (6, 'Bandage', 120.00);
SELECT * FROM Products;
Inilah output lengkap dari terminal saya ketika saya menjalankan ini:
sqlite> DELETE FROM Products; sqlite> sqlite> INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 8.00); sqlite> INSERT OR ABORT INTO Products VALUES (2, 'Nails', 2.50); sqlite> INSERT OR ABORT INTO Products VALUES (3, 'Saw', 10.50); sqlite> INSERT OR ABORT INTO Products VALUES (1, 'Wrench', 22.50); Error: UNIQUE constraint failed: Products.ProductId sqlite> INSERT OR ABORT INTO Products VALUES (5, 'Chisel', 23.00); sqlite> INSERT OR ABORT INTO Products VALUES (6, 'Bandage', 120.00); sqlite> sqlite> SELECT * FROM Products; ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0 2 Nails 2.5 3 Saw 10.5 5 Chisel 23.0 6 Bandage 120.0 sqlite>
Opsi Gagal
FAIL
opsi membatalkan pernyataan SQL saat ini dengan kesalahan SQLITE_CONSTRAINT. Tetapi opsi ini tidak membatalkan perubahan sebelumnya dari pernyataan SQL yang gagal dan juga tidak mengakhiri transaksi.
DELETE FROM Products;
INSERT OR FAIL INTO Products VALUES
(1, 'Hammer', 8.00),
(2, 'Nails', 2.50),
(3, 'Saw', 10.50),
(1, 'Wrench', 22.50),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products;
Hasil:
ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0 2 Nails 2.5 3 Saw 10.5