SQLite có ON CONFLICT
mệnh đề cho phép bạn chỉ định cách xử lý xung đột ràng buộc. Nó áp dụng cho UNIQUE
, NOT NULL
, CHECK
và PRIMARY KEY
ràng buộc (nhưng không phải FOREIGN KEY
ràng buộc).
Có năm tùy chọn khả thi mà bạn có thể sử dụng với điều khoản này:
-
ABORT
-
FAIL
-
IGNORE
-
REPLACE
-
ROLLBACK
Bài viết này cung cấp các ví dụ và giải thích về từng tùy chọn này.
ON CONFLICT
mệnh đề được sử dụng trong CREATE TABLE
nhưng nó cũng có thể được sử dụng khi chèn hoặc cập nhật dữ liệu bằng cách thay thế ON CONFLICT
với OR
.
Khi tạo bảng
Như đã đề cập, bạn có thể sử dụng ON CONFLICT
khi bạn tạo bảng hoặc khi bạn chèn / cập nhật dữ liệu.
Đây là một ví dụ về việc sử dụng ON CONFLICT
tại thời điểm tạo bảng.
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL ON CONFLICT IGNORE,
Price
);
Khi bạn sử dụng ON CONFLICT
, bạn áp dụng nó cho ràng buộc cụ thể mà bạn muốn xử lý. Trong trường hợp này, tôi đã thêm mệnh đề vào NOT NULL
ràng buộc.
Trong trường hợp này, tôi đã chỉ định IGNORE
, có nghĩa là, nếu có vi phạm ràng buộc, SQLite sẽ bỏ qua hàng đó và sau đó tiếp tục xử lý.
Bây giờ nếu tôi cố gắng chèn NULL
vào Tên sản phẩm cột mà hàng bị bỏ qua.
INSERT INTO Products VALUES
(1, 'Hammer', 9.99),
(2, NULL, 1.49),
(3, 'Saw', 11.34),
(4, 'Wrench', 37.00),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products;
Kết quả:
ProductId ProductName Giá ------------------------------ 1 Búa 9,99 3 Cưa 11,34 4 Cờ lê 37,0 5 Đục 23,0 6 Băng keo 120.0
Khi chèn dữ liệu
Bạn cũng có thể sử dụng mệnh đề này khi chèn và cập nhật dữ liệu. Sự khác biệt là bạn thay thế ON CONFLICT
với OR
.
Để chứng minh, tôi sẽ thả bảng trước đó và tạo lại nó, nhưng không có ON CONFLICT
mệnh đề:
DROP TABLE IF EXISTS Products;
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL,
Price
);
Bây giờ tôi sẽ chèn cùng một dữ liệu và sử dụng OR IGNORE
để bỏ qua hàng vi phạm ràng buộc.
INSERT OR IGNORE INTO Products VALUES
(1, 'Hammer', 9.99),
(2, NULL, 1.49),
(3, 'Saw', 11.34),
(4, 'Wrench', 37.00),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products;
Kết quả:
ProductId ProductName Giá ------------------------------ 1 Búa 9,99 3 Cưa 11,34 4 Cờ lê 37,0 5 Đục 23,0 6 Băng keo 120.0
Vì vậy, chúng tôi nhận được kết quả tương tự như trong ví dụ trước.
Trong các ví dụ này, tôi đã sử dụng IGNORE
lựa chọn. Đây chỉ là một trong năm lựa chọn khả thi cho điều khoản này.
Dưới đây là các ví dụ sử dụng từng tùy chọn trong số năm tùy chọn.
Hủy bỏ
Tùy chọn này hủy bỏ câu lệnh SQL hiện tại với lỗi SQLITE_CONSTRAINT và sao lưu bất kỳ thay đổi nào được thực hiện bởi câu lệnh SQL hiện tại; nhưng những thay đổi do các câu lệnh SQL trước đó gây ra trong cùng một giao dịch được giữ nguyên và giao dịch vẫn hoạt động.
Đây là hành vi mặc định. Nói cách khác, đây là những gì xảy ra khi vi phạm ràng buộc khi bạn không sử dụng ON CONFLICT
mệnh đề.
Dưới đây là một ví dụ về những gì sẽ xảy ra khi bạn chỉ định ABORT
.
DELETE FROM Products;
INSERT OR ABORT INTO Products VALUES
(1, 'Hammer', 9.99),
(2, NULL, 1.49),
(3, 'Saw', 11.34),
(4, 'Wrench', 37.00),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products;
Kết quả:
Không có kết quả nào được trả về vì INSERT
thao tác đã bị hủy bỏ và bảng do đó trống.
Đây là những gì sẽ xảy ra nếu tôi đặt mỗi hàng trong INSERT
của riêng nó tuyên bố trong một giao dịch.
BEGIN TRANSACTION;
INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 9.99);
INSERT OR ABORT INTO Products VALUES (2, NULL, 1.49);
INSERT OR ABORT INTO Products VALUES (3, 'Saw', 11.34);
INSERT OR ABORT INTO Products VALUES (4, 'Wrench', 37.00);
INSERT OR ABORT INTO Products VALUES (5, 'Chisel', 23.00);
INSERT OR ABORT INTO Products VALUES (6, 'Bandage', 120.00);
COMMIT;
SELECT * FROM Products;
Kết quả:
ProductId ProductName Giá ------------------------------ 1 Búa 9,99 3 Cưa 11,34 4 Cờ lê 37,0 5 Đục 23,0 6 Băng keo 120.0
Không thành công
FAIL
tùy chọn hủy bỏ câu lệnh SQL hiện tại với lỗi SQLITE_CONSTRAINT. Nhưng nó không hỗ trợ các thay đổi trước đó của câu lệnh SQL không thành công cũng như không kết thúc giao dịch.
Đây là một ví dụ.
DELETE FROM Products;
INSERT OR FAIL INTO Products VALUES
(1, 'Hammer', 9.99),
(2, NULL, 1.49),
(3, 'Saw', 11.34),
(4, 'Wrench', 37.00),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products;
Kết quả:
ProductId ProductName Giá ------------------------------ 1 Hammer 9,99
Đây là nó với INSERT
riêng biệt báo cáo trong một giao dịch.
DELETE FROM Products;
BEGIN TRANSACTION;
INSERT OR FAIL INTO Products VALUES (1, 'Hammer', 9.99);
INSERT OR FAIL INTO Products VALUES (2, NULL, 1.49);
INSERT OR FAIL INTO Products VALUES (3, 'Saw', 11.34);
INSERT OR FAIL INTO Products VALUES (4, 'Wrench', 37.00);
INSERT OR FAIL INTO Products VALUES (5, 'Chisel', 23.00);
INSERT OR FAIL INTO Products VALUES (6, 'Bandage', 120.00);
COMMIT;
SELECT * FROM Products;
Kết quả:
ProductId ProductName Giá ------------------------------ 1 Búa 9,99 3 Cưa 11,34 4 Cờ lê 37,0 5 Đục 23,0 6 Băng keo 120.0
Bỏ qua
IGNORE
tùy chọn bỏ qua một hàng có vi phạm ràng buộc và tiếp tục xử lý các hàng tiếp theo của câu lệnh SQL như thể không có gì sai. Các hàng khác trước và sau hàng có vi phạm ràng buộc được chèn hoặc cập nhật bình thường. Không có lỗi nào được trả về cho tính duy nhất, NOT NULL
và UNIQUE
lỗi ràng buộc khi tùy chọn này được sử dụng. Tuy nhiên, tùy chọn này hoạt động giống như ABORT
đối với lỗi ràng buộc khóa ngoại.
Các ví dụ đầu tiên trên trang này sử dụng IGNORE
, nhưng nó lại ở đây.
DELETE FROM Products;
INSERT OR IGNORE INTO Products VALUES
(1, 'Hammer', 9.99),
(2, NULL, 1.49),
(3, 'Saw', 11.34),
(4, 'Wrench', 37.00),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products;
Kết quả:
ProductId ProductName Giá ------------------------------ 1 Búa 9,99 3 Cưa 11,34 4 Cờ lê 37,0 5 Đục 23,0 6 Băng keo 120.0
Thay thế
REPLACE
tùy chọn hoạt động khác nhau tùy thuộc vào vi phạm:
- Khi một
UNIQUE
hoặcPRIMARY KEY
vi phạm ràng buộc xảy ra,REPLACE
tùy chọn xóa các hàng tồn tại trước đó gây ra vi phạm ràng buộc trước khi chèn hoặc cập nhật hàng hiện tại và lệnh tiếp tục thực thi bình thường. - Nếu một
NOT NULL
vi phạm ràng buộc xảy ra, nó thay thếNULL
giá trị với giá trị mặc định cho cột đó hoặc nếu cột không có giá trị mặc định, thìABORT
thuật toán được sử dụng. - Nếu một
CHECK
ràng buộc hoặc vi phạm ràng buộc khóa ngoại xảy ra, sau đóREPLACE
hoạt động giống nhưABORT
.
Ngoài ra, nếu nó xóa các hàng để đáp ứng một hạn chế, hãy xóa trình kích hoạt kích hoạt nếu và chỉ khi trình kích hoạt đệ quy được bật.
Đây là một ví dụ sử dụng REPLACE
lựa chọn.
DELETE FROM Products;
INSERT OR REPLACE INTO Products VALUES
(1, 'Hammer', 9.99),
(2, 'Nails', 1.49),
(3, 'Saw', 11.34),
(1, 'Wrench', 37.00),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products;
Kết quả:
ProductId ProductName Giá ------------------------------ 1 Cờ lê 37.0 2 Đinh 1.49 3 Cưa 11.34 5 Đục 23.0 6 Băng keo 120.0
Trong ví dụ này, xung đột là với khóa chính (tôi đã cố gắng chèn hai hàng có cùng một ProductId ). REPLACE
khiến tùy chọn thứ hai thay thế tùy chọn đầu tiên.
Khôi phục
Một tùy chọn khác là sử dụng ROLLBACK
.
Tùy chọn này hủy bỏ câu lệnh SQL hiện tại với lỗi SQLITE_CONSTRAINT và khôi phục giao dịch hiện tại. Nếu không có giao dịch nào đang hoạt động (ngoài giao dịch ngụ ý được tạo trên mọi lệnh) thì giao dịch đó hoạt động giống như ABORT
thuật toán.
Dưới đây là một ví dụ sử dụng nhiều INSERT OR ROLLBACK
báo cáo trong một giao dịch.
DELETE FROM Products;
BEGIN TRANSACTION;
INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 9.99);
INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49);
INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34);
INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00);
INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00);
INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);
COMMIT;
SELECT * FROM Products;
Đây là kết quả đầu ra đầy đủ từ thiết bị đầu cuối của tôi khi tôi chạy điều này:
sqlite> XÓA KHỎI Sản phẩm; sqlite> sqlite> BẮT ĐẦU GIAO DỊCH; sqlite> CHÈN HOẶC ROLLBACK VÀO GIÁ TRỊ Sản phẩm (1, 'Hammer', 9,99); sqlite> CHÈN HOẶC QUAY LẠI VÀO GIÁ TRỊ Sản phẩm (2, NULL, 1.49); Lỗi:Ràng buộc NOT NULL không thành công:Products.ProductNamesqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34); sqlite> INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37,00); sqlite> INSERT OR ROLLBACK VÀO GIÁ TRỊ Sản phẩm (5, 'Chisel', 23,00); sqlite> CHÈN HOẶC ROLLBACK VÀO GIÁ TRỊ Sản phẩm (6, 'Bandage', 120,00); sqlite> COMMIT; Lỗi:không thể cam kết - không có giao dịch nào được kích hoạt> sqlite> CHỌN * TỪ Products; ProductId ProductName Price trước>Vì vậy, nó đã vi phạm ràng buộc, sau đó quay trở lại giao dịch. Sau đó, các dòng tiếp theo được xử lý và sau đó là
COMMIT
từ khóa đã gặp phải. Đến lúc đó, giao dịch đã được khôi phục và do đó, chúng tôi gặp một lỗi khác cho chúng tôi biết rằng không có giao dịch nào đang hoạt động.Đây là những gì sẽ xảy ra nếu tôi xóa nó khỏi giao dịch.
DELETE FROM Products; INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 9.99); INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49); INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34); INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00); INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00); INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00); SELECT * FROM Products;
Đây là kết quả đầu ra đầy đủ từ thiết bị đầu cuối của tôi khi tôi chạy điều này:
sqlite> XÓA KHỎI Sản phẩm; sqlite> sqlite> CHÈN HOẶC QUAY LẠI VÀO GIÁ TRỊ Sản phẩm (1, 'Hammer', 9,99); sqlite> CHÈN HOẶC LĂN LẠI VÀO GIÁ TRỊ Sản phẩm (2, NULL, 1.49); Lỗi:Ràng buộc KHÔNG ĐỦ không thành công:Products.ProductNamesqlite> INSERT HOẶC QUAY LẠI VÀO GIÁ TRỊ Sản phẩm (3, 'Saw', 11,34); sqlite> CHÈN HOẶC ROLLBACK VÀO GIÁ TRỊ Sản phẩm (4, 'Cờ lê', 37,00); sqlite> CHÈN HOẶC ROLLBACK VÀO GIÁ TRỊ Sản phẩm (5 , 'Chisel', 23.00); sqlite> CHÈN HOẶC QUAY LẠI VÀO GIÁ TRỊ Sản phẩm (6, 'Bandage', 120.00); sqlite> sqlite> CHỌN * TỪ Sản phẩm; ProductId ProductName Giá ---------- - --------- ---------- 1 Búa 9,99 3 Cưa 11,34 4 Cờ lê 37,0 5 Đục 23,0 6 Băng 120,0Trong trường hợp này, nó hoạt động giống như
ABORT
.Để xác nhận, đây là câu lệnh tương tự sử dụng
ABORT
thay vìROLLBACK
.DELETE FROM Products; INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 9.99); INSERT OR ABORT INTO Products VALUES (2, NULL, 1.49); INSERT OR ABORT INTO Products VALUES (3, 'Saw', 11.34); INSERT OR ABORT INTO Products VALUES (4, 'Wrench', 37.00); INSERT OR ABORT INTO Products VALUES (5, 'Chisel', 23.00); INSERT OR ABORT INTO Products VALUES (6, 'Bandage', 120.00); SELECT * FROM Products;
Đây là kết quả đầu ra đầy đủ từ thiết bị đầu cuối của tôi khi tôi chạy điều này:
sqlite> XÓA TỪ SẢN PHẨM; sqlite> sqlite> CHÈN HOẶC NHẬP VÀO GIÁ TRỊ Sản phẩm (1, 'Hammer', 9,99); sqlite> CHÈN HOẶC NHẬP VÀO GIÁ TRỊ Sản phẩm (2, NULL, 1.49); Lỗi:Ràng buộc NOT NULL không thành công:Products.ProductNamesqlite> CHÈN HOẶC NHẬP VÀO GIÁ TRỊ Sản phẩm (3, 'Saw', 11,34); sqlite> CHÈN HOẶC NHẬP VÀO GIÁ TRỊ Sản phẩm (4, 'Cờ lê', 37,00); sqlite> CHÈN HOẶC NHẬP VÀO GIÁ TRỊ Sản phẩm (5 , 'Chisel', 23,00); sqlite> CHÈN HOẶC NHẬP VÀO GIÁ TRỊ Sản phẩm (6, 'Bandage', 120,00); sqlite> sqlite> CHỌN * TỪ Sản phẩm; ProductId ProductName Giá ---------- - --------- ---------- 1 Búa 9,99 3 Cưa 11,34 4 Cờ lê 37,0 5 Đục 23,0 6 Băng 120,0