Trong SQLite, một AUTOINCREMENT
là cột sử dụng giá trị tăng tự động cho mỗi hàng được chèn vào bảng.
Có một số cách bạn có thể tạo AUTOINCREMENT
cột:
- Bạn có thể tạo nó một cách hoàn toàn khi bạn xác định cột là
INTEGER PRIMARY KEY
. - Bạn có thể tạo nó một cách rõ ràng bằng
AUTOINCREMENT
từ khóa. Một nhược điểm của phương pháp này là nó sử dụng thêm CPU, bộ nhớ, dung lượng ổ đĩa và chi phí I / O của ổ đĩa.
Cả hai phương pháp đều khiến cột sử dụng giá trị tăng dần mỗi khi chèn một hàng mới bằng NULL
trong cột đó.
Tuy nhiên, có một số khác biệt nhỏ giữa cách hoạt động của mỗi phương pháp.
Không có Từ khóa AUTOINCREMENT
Khi bạn khai báo một cột là INTEGER PRIMARY KEY
, nó sẽ tự động tăng lên. Do đó, bạn thực sự không cần sử dụng AUTOINCREMENT
từ khóa để có một cột sử dụng giá trị tăng tự động cho mỗi hàng.
Khi bạn làm điều này, bất kỳ NULL
nào các giá trị được chuyển đổi thành ROWID
hiện tại . Nói cách khác, nếu bạn chèn NULL
vào cột đó, nó sẽ được chuyển đổi thành ROWID
hiện tại .
Trên thực tế, cách hoạt động là cột trở thành bí danh cho ROWID
. Bạn có thể truy cập ROWID
giá trị bằng cách sử dụng bất kỳ tên nào trong bốn tên; tên cột, ROWID
, _ROWID_
hoặc OID
.
Một lợi ích của việc bỏ qua AUTOINCREMENT
từ khóa là nó làm giảm chi phí CPU, bộ nhớ, không gian đĩa và ổ đĩa I / O.
Tuy nhiên, một nhược điểm quan trọng là bạn không thể đảm bảo rằng tất cả các hàng sẽ được tăng dần theo thứ tự tăng dần. Điều này là do cách tự động tăng dần hoạt động khi bỏ qua AUTOINCREMENT
từ khóa so với sử dụng từ khóa đó.
Khi bạn bỏ qua AUTOINCREMENT
từ khóa, một lần ROWID
bằng số nguyên lớn nhất có thể (9223372036854775807), SQLite sẽ cố gắng tìm một ROWID
dương chưa sử dụng một cách ngẫu nhiên.
Tuy nhiên, miễn là bạn không bao giờ sử dụng ROWID
tối đa giá trị và bạn không bao giờ xóa mục nhập trong bảng có ROWID
lớn nhất , phương pháp này sẽ tạo ra ROWID
duy nhất tăng một cách đơn điệu s.
Với từ khóa AUTOINCREMENT
Bạn cũng có thể tạo các cột tự động tăng dần một cách rõ ràng. Để thực hiện việc này, hãy sử dụng AUTOINCREMENT
từ khóa.
Khi bạn sử dụng phương pháp này, một thuật toán hơi khác sẽ được sử dụng để xác định giá trị tự động tăng dần.
Khi bạn sử dụng AUTOINCREMENT
từ khóa, ROWID
được chọn cho hàng mới lớn hơn ít nhất một hàng so với ROWID
lớn nhất điều đó đã từng trước khi tồn tại trong cùng một bảng đó.
Nói cách khác, nó sẽ không quay lại và sử dụng lại ROWID
đã xóa trước đó các giá trị. Khi ROWID
lớn nhất có thể đã được chèn, không được phép chèn mới. Mọi nỗ lực chèn một hàng mới sẽ không thành công với SQLITE_FULL
lỗi.
Do đó, sử dụng phương pháp này đảm bảo rằng ROWID
s đang tăng đơn điệu. Nói cách khác, bạn có thể dựa vào phương pháp này để có ROWID
s theo thứ tự tăng dần.
Tuy nhiên, điều này không có nghĩa là các giá trị sẽ luôn tăng lên 1. Nó chỉ có nghĩa là chúng sẽ không bao giờ giảm.
Ví dụ
Dưới đây là một ví dụ để chứng minh sự khác biệt giữa xác định rõ ràng và rõ ràng cột tự động tăng.
CREATE TABLE Cats(
CatId INTEGER PRIMARY KEY,
CatName
);
CREATE TABLE Dogs(
DogId INTEGER PRIMARY KEY AUTOINCREMENT,
DogName
);
INSERT INTO Cats VALUES
( NULL, 'Brush' ),
( NULL, 'Scarcat' ),
( NULL, 'Flutter' );
INSERT INTO Dogs VALUES
( NULL, 'Yelp' ),
( NULL, 'Woofer' ),
( NULL, 'Fluff' );
SELECT * FROM Cats;
SELECT * FROM Dogs;
Kết quả ban đầu:
CatId CatName ---------- ---------- 1 Brush 2 Scarcat 3 Flutter DogId DogName ---------- ---------- 1 Yelp 2 Woofer 3 Fluff
Bây giờ, hãy xóa hàng cuối cùng trong mỗi bảng, chèn lại các hàng, sau đó chọn kết quả:
DELETE FROM Cats WHERE CatId = 3;
DELETE FROM Dogs WHERE DogId = 3;
INSERT INTO Cats VALUES ( NULL, 'New Flutter' );
INSERT INTO Dogs VALUES ( NULL, 'New Fluff' );
SELECT * FROM Cats;
SELECT * FROM Dogs;
Kết quả:
CatId CatName ---------- ---------- 1 Brush 2 Scarcat 3 New Flutter DogId DogName ---------- ---------- 1 Yelp 2 Woofer 4 New Fluff
Tóm lại, Mèo bảng đã được tạo không có AUTOINCREMENT
từ khóa và Chó bảng đã được tạo với AUTOINCREMENT
từ khóa.
Sau khi xóa hàng cuối cùng khỏi Mèo bảng, INSERT
tiếp theo hoạt động dẫn đến cùng một ROWID
đang được sử dụng lại cho hàng đó.
Tuy nhiên, Những chú chó bảng đã khác. Nó được tạo bằng AUTOINCREMENT
từ khóa và do đó nó không thể sử dụng lại giá trị trước đó. Nó chỉ đơn giản là tăng lên giá trị tiếp theo, để lại khoảng trống trong việc đánh số.
ROWID tối đa
Chúng ta có thể lấy ví dụ trước đó thêm một bước và chèn một hàng mới bằng cách sử dụng rõ ràng ROWID
tối đa có thể.
INSERT INTO Cats VALUES ( 9223372036854775807, 'Magnus' );
INSERT INTO Dogs VALUES ( 9223372036854775807, 'Maximus' );
SELECT * FROM Cats;
SELECT * FROM Dogs;
Kết quả:
CatId CatName -------------------- -------------------- 1 Brush 2 Scarcat 3 New Flutter 9223372036854775807 Magnus DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 9223372036854775807 Maximus
Được, vì vậy cả hai bảng đều sử dụng số nguyên lớn nhất có thể làm ROWID
lớn nhất của chúng giá trị.
Hãy xem điều gì sẽ xảy ra khi tôi cố gắng chèn một hàng mới vào mỗi bảng (mà không chỉ định rõ ràng giá trị cho các cột tự động tăng dần).
Chèn vào Mèo bảng:
INSERT INTO Cats VALUES ( NULL, 'Scratchy' );
SELECT * FROM Cats;
Kết quả:
CatId CatName -------------------- -------------------- 1 Brush 2 Scarcat 3 New Flutter 267244677462397326 Scratchy 9223372036854775807 Magnus
Vì vậy, Mèo bảng đã thành công. Tuy nhiên, hãy lưu ý rằng giá trị tự động tăng mới thấp hơn giá trị trước đó (nó không có tùy chọn nào khác).
Nếu không có bất kỳ cột nào khác để ghi lại ngày / giờ mà hàng được chèn / cập nhật, người ta có thể cho rằng Magnus không chính xác được chèn sau Scratchy .
Bây giờ, hãy thử chèn một hàng mới vào Chó bảng:
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );
Kết quả:
Error: database or disk is full
Vì vậy, chúng tôi nhận được một kết quả khác với Mèo bảng.
Tôi gặp lỗi này vì ROWID
lớn nhất có thể đã được sử dụng trong bảng và vì bảng này được tạo bằng AUTOINCREMENT
từ khóa, nó sẽ không quay lại và tìm kiếm ROWID
không sử dụng giá trị.
SELECT * FROM Dogs;
Kết quả:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 9223372036854775807 Maximus
Hơn nữa, tôi sẽ tiếp tục gặp lỗi này, ngay cả khi tôi xóa Maximus từ bảng (tức là con chó có ROWID
tối đa giá trị).
Hãy thử nó:
DELETE FROM Dogs WHERE DogId = 9223372036854775807;
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );
Kết quả:
Error: database or disk is full
Vì vậy, không chỉ chúng tôi gặp lỗi mà tôi còn xóa Maximus :
SELECT * FROM Dogs;
Kết quả:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff
Điều quan trọng cần lưu ý là điều này sẽ xảy ra ngay cả khi tôi thay đổi ROWID
giá trị thành giá trị thấp hơn. Thực tế là tôi đã sử dụng ROWID là 9223372036854775807 có nghĩa là AUTOINCREMENT
sẽ không tự động tăng nữa.
Điều này là do AUTOINCREMENT
chỉ sử dụng các giá trị cao hơn ít nhất một giá trị so với bất kỳ giá trị nào đã từng tồn tại trước đó trong cùng một bảng đó .
Từ bây giờ, nếu tôi muốn tiếp tục chèn giá trị vào cột này, tôi sẽ cần phải chèn giá trị một cách rõ ràng. Điều này giả định rằng tôi chưa có 9223372036854775807 hàng trong bảng.
Hãy lắp lại Maximus với ROWID
thấp hơn và thử lại:
INSERT INTO Dogs VALUES ( 5, 'Maximus' );
SELECT * FROM Dogs;
Kết quả:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 5 Maximus
Bây giờ, hãy thử chèn Có thể liếm được một lần nữa, sử dụng AUTOINCREMENT
:
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );
Kết quả:
Error: database or disk is full
Vì vậy, mặc dù tôi đã xóa hàng chứa ROWID
tối đa giá trị 9223372036854775807, nó vẫn ngăn tôi tự động tăng cột.
Đây chính xác là cách nó được thiết kế. ROWID
tối đa trước đây đã ở trong bảng này và vì vậy AUTOINCREMENT
sẽ không tự động tăng trở lại trong bảng đó.
Cách duy nhất để thêm một hàng mới vào bảng đó là chèn ROWID
theo cách thủ công giá trị.
INSERT INTO Dogs VALUES (6, 'Lickable');
SELECT * FROM Dogs;
Kết quả:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 5 Maximus 6 Lickable