SQLite
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> SQLite

Cách AUTOINCREMENT hoạt động trong SQLite

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            


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. android.database.CursorIndexOutOfBoundsException

  2. Không hài lòngLinkError trong phương pháp gốc

  3. SQL:Sắp xếp theo mức độ ưu tiên, nhưng đặt 0 ở cuối cùng

  4. Đặt giá trị mặc định của một cột số nguyên SQLite

  5. Cơ sở dữ liệu được điền sẵn không hoạt động ở API 28 không có ngoại lệ bảng nào như vậy