Ràng buộc bảng SQLite - duy nhất trên nhiều cột


179

Tôi có thể tìm thấy cú pháp "biểu đồ" về điều này trên trang web SQLite, nhưng không có ví dụ nào và mã của tôi bị lỗi. Tôi có các bảng khác với các ràng buộc duy nhất trên một cột, nhưng tôi muốn thêm một ràng buộc cho bảng trên hai cột. Đây là những gì tôi có đang gây ra SQLiteException với thông báo "lỗi cú pháp".

CREATE TABLE name (column defs) 
UNIQUE (col_name1, col_name2) ON CONFLICT REPLACE

Tôi đang làm điều này dựa trên những điều sau đây:

hạn chế bảng

Để rõ ràng, tài liệu về liên kết tôi cung cấp nói rằng CONTSTRAINT namephải đi trước định nghĩa ràng buộc của tôi.

Một cái gì đó có thể dẫn đến giải pháp mặc dù là bất cứ điều gì tuân theo các định nghĩa cột được ngoặc đơn của tôi là những gì trình gỡ lỗi phàn nàn.

Nếu tôi đặt

...last_column_name last_col_datatype) CONSTRAINT ...

lỗi gần "CONSTRAINT": lỗi cú pháp

Nếu tôi đặt

...last_column_name last_col_datatype) UNIQUE ...

lỗi gần "UNIQUE": lỗi cú pháp


1
UNIQUE bị thiếu dấu phẩy trước khi bắt đầu ..
Majid Bashir

Câu trả lời:


345

Đặt khai báo ĐỘC ĐÁO trong phần định nghĩa cột; ví dụ làm việc:

CREATE TABLE a (
    i INT,
    j INT,
    UNIQUE(i, j) ON CONFLICT REPLACE
);

6
Câu trả lời hay +1. Liệu cú pháp tạo này có cho phép tôi sử dụng phương thức chèn thông thường và không phải là insertWithOnConflict với cờ SQLiteDatabase.CONFLICT_REPLACE không?
Oleg Belousov

3
Tôi đang sử dụng ON CONFLICT IGNORE(chưa thử thay thế) với hơn 2 cột, nhưng tôi không thấy nó tôn trọng ràng buộc duy nhất, nó chỉ vui vẻ thêm các bản sao.
Michael

5
rõ ràng bởi vì tôi có các cột NULL và điều đó chỉ bắn ra cửa sổ duy nhất
Michael

Coi chừng sử dụng ON CONFLICT REPLACEnó có thể không phải là những gì bạn muốn - nó xóa các hàng có sẵn để cho phép hàng mới được chèn vào. Thông thường, tôi muốn ABORT hoặc ROLLBACK vi phạm ràng buộc. Mệnh đề SQLite ON CONFLICT
karmakaze

9

Chà, cú pháp của bạn không khớp với liên kết bạn đưa vào, chỉ định:

 CREATE TABLE name (column defs) 
    CONSTRAINT constraint_name    -- This is new
    UNIQUE (col_name1, col_name2) ON CONFLICT REPLACE

Ban đầu tôi đã làm điều đó ... không hiệu quả. Tôi đã thử lại lần nữa chỉ trong trường hợp ... vẫn không hoạt động
Rich

1

Hãy cẩn thận cách bạn xác định bảng cho bạn sẽ nhận được kết quả khác nhau khi chèn. Hãy xem xét những điều sau đây



CREATE TABLE IF NOT EXISTS t1 (id INTEGER PRIMARY KEY, a TEXT UNIQUE, b TEXT);
INSERT INTO t1 (a, b) VALUES
    ('Alice', 'Some title'),
    ('Bob', 'Palindromic guy'),
    ('Charles', 'chucky cheese'),
    ('Alice', 'Some other title') 
    ON CONFLICT(a) DO UPDATE SET b=excluded.b;
CREATE TABLE IF NOT EXISTS t2 (id INTEGER PRIMARY KEY, a TEXT UNIQUE, b TEXT, UNIQUE(a) ON CONFLICT REPLACE);
INSERT INTO t2 (a, b) VALUES
    ('Alice', 'Some title'),
    ('Bob', 'Palindromic guy'),
    ('Charles', 'chucky cheese'),
    ('Alice', 'Some other title');

$ sqlite3 test.sqlite
SQLite version 3.28.0 2019-04-16 19:49:53
Enter ".help" for usage hints.
sqlite> CREATE TABLE IF NOT EXISTS t1 (id INTEGER PRIMARY KEY, a TEXT UNIQUE, b TEXT);
sqlite> INSERT INTO t1 (a, b) VALUES
   ...>     ('Alice', 'Some title'),
   ...>     ('Bob', 'Palindromic guy'),
   ...>     ('Charles', 'chucky cheese'),
   ...>     ('Alice', 'Some other title') 
   ...>     ON CONFLICT(a) DO UPDATE SET b=excluded.b;
sqlite> CREATE TABLE IF NOT EXISTS t2 (id INTEGER PRIMARY KEY, a TEXT UNIQUE, b TEXT, UNIQUE(a) ON CONFLICT REPLACE);
sqlite> INSERT INTO t2 (a, b) VALUES
   ...>     ('Alice', 'Some title'),
   ...>     ('Bob', 'Palindromic guy'),
   ...>     ('Charles', 'chucky cheese'),
   ...>     ('Alice', 'Some other title');
sqlite> .mode col
sqlite> .headers on
sqlite> select * from t1;
id          a           b               
----------  ----------  ----------------
1           Alice       Some other title
2           Bob         Palindromic guy 
3           Charles     chucky cheese   
sqlite> select * from t2;
id          a           b              
----------  ----------  ---------------
2           Bob         Palindromic guy
3           Charles     chucky cheese  
4           Alice       Some other titl
sqlite> 

Mặc dù hiệu ứng chèn / cập nhật là như nhau, nhưng các idthay đổi dựa trên loại định nghĩa bảng (xem bảng thứ hai nơi 'Alice' hiện có id = 4; bảng đầu tiên thực hiện nhiều hơn những gì tôi mong đợi, giữ nguyên PRIMARY KEY ). Hãy nhận biết hiệu ứng này.


1

Nếu bạn đã có một bảng và không thể / không muốn tạo lại nó vì bất kỳ lý do gì, hãy sử dụng các chỉ mục :

CREATE UNIQUE INDEX my_index ON my_table(col_1, col_2);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.