В SQLite, AUTOINCREMENT
колоната е тази, която използва автоматично увеличена стойност за всеки ред, който е вмъкнат в таблицата.
Има няколко начина, по които можете да създадете AUTOINCREMENT
колона:
- Можете да го създадете имплицитно, когато дефинирате колоната като
INTEGER PRIMARY KEY
. - Можете да го създадете изрично с
AUTOINCREMENT
ключова дума. Един недостатък на този метод е, че използва допълнителен процесор, памет, дисково пространство и дискови входно/изходни разходи.
И двата метода карат колоната да използва нарастваща стойност всеки път, когато се вмъкне нов ред с NULL
в тази колона.
Има обаче някои фини разлики между начина, по който работи всеки метод.
Без ключовата дума AUTOINCREMENT
Когато декларирате колона като INTEGER PRIMARY KEY
, той автоматично ще се увеличи. Следователно всъщност не е необходимо да използвате AUTOINCREMENT
ключова дума, за да има колона, която използва автоматично нарастваща стойност за всеки ред.
Когато направите това, всеки NULL
стойностите се преобразуват в текущия ROWID
. С други думи, ако въведете NULL
в тази колона, тя ще бъде преобразувана в текущия ROWID
.
Всъщност начинът, по който работи е, че колоната става псевдоним за ROWID
. Можете да получите достъп до ROWID
стойност, като използвате някое от четирите имена; името на колоната, ROWID
, _ROWID_
или OID
.
Едно предимство от пропускането на AUTOINCREMENT
ключова дума е, че намалява процесора, паметта, дисковото пространство и разходите за вход/изход на диска.
Важен недостатък обаче е, че не можете да гарантирате, че всички редове ще бъдат увеличени във възходящ ред. Това се дължи на начина, по който работи автоматичното увеличаване при пропускане на AUTOINCREMENT
ключова дума спрямо използването на тази ключова дума.
Когато пропуснете AUTOINCREMENT
ключова дума, веднъж ROWID
е равно на възможно най-голямото цяло число (9223372036854775807), SQLite ще се опита да намери неизползван положителен ROWID
на случаен принцип.
Въпреки това, стига никога да не използвате максималния ROWID
стойност и никога не изтривате записа в таблицата с най-големия ROWID
, този метод ще генерира монотонно нарастващ уникален ROWID
с.
С ключовата дума AUTOINCREMENT
Можете също така изрично да създавате автоматично увеличаващи се колони. За да направите това, използвайте AUTOINCREMENT
ключова дума.
Когато използвате този метод, се използва малко по-различен алгоритъм за определяне на автоматично увеличената стойност.
Когато използвате AUTOINCREMENT
ключова дума, ROWID
избраният за новия ред е поне един по-голям от най-големия ROWID
което е някога преди е съществувал в същата таблица.
С други думи, няма да се върне и да използва повторно изтрития ROWID
стойности. Веднъж възможно най-големият ROWID
е вмъкнат, не са разрешени нови вмъквания. Всеки опит за вмъкване на нов ред ще се провали с SQLITE_FULL
грешка.
Следователно използването на този метод гарантира, че ROWID
s се увеличават монотонно. С други думи, можете да разчитате на този метод за наличието на ROWID
s във възходящ ред.
Това обаче не означава, че стойностите винаги ще се увеличават с 1. Това просто означава, че те никога няма да намалеят.
Пример
Ето пример за демонстриране на разликата между имплицитно и изрично дефиниране на колона с автоматично увеличение.
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;
Първоначален резултат:
CatId CatName ---------- ---------- 1 Brush 2 Scarcat 3 Flutter DogId DogName ---------- ---------- 1 Yelp 2 Woofer 3 Fluff
Сега нека изтрием последния ред във всяка таблица, вмъкнете редовете отново, след което изберете резултата:
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;
Резултат:
CatId CatName ---------- ---------- 1 Brush 2 Scarcat 3 New Flutter DogId DogName ---------- ---------- 1 Yelp 2 Woofer 4 New Fluff
За да обобщим, Котките таблицата е създадена без AUTOINCREMENT
ключова дума и Кучета таблицата е създадена с AUTOINCREMENT
ключова дума.
След като изтриете последния ред от Котки таблица, следващият INSERT
операцията доведе до същия ROWID
се използва повторно за този ред.
Въпреки това, вкучетата масата беше различна. Създаден е с AUTOINCREMENT
ключова дума и следователно не може да използва повторно предишната стойност. Просто се увеличава до следващата стойност, оставяйки празнина в номерацията.
Максимален ROWID
Можем да вземем предишния пример още една стъпка и да вмъкнем нов ред, като изрично използваме максималния ROWID
възможно.
INSERT INTO Cats VALUES ( 9223372036854775807, 'Magnus' );
INSERT INTO Dogs VALUES ( 9223372036854775807, 'Maximus' );
SELECT * FROM Cats;
SELECT * FROM Dogs;
Резултат:
CatId CatName -------------------- -------------------- 1 Brush 2 Scarcat 3 New Flutter 9223372036854775807 Magnus DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 9223372036854775807 Maximus
Добре, така че и двете таблици използват най-голямото възможно цяло число като най-голямото им ROWID
стойности.
Нека видим какво се случва, когато се опитам да вмъкна нов ред във всяка таблица (без изрично да посоча стойност за автоматично увеличаващите се колони).
Вмъкнете в Котки таблица:
INSERT INTO Cats VALUES ( NULL, 'Scratchy' );
SELECT * FROM Cats;
Резултат:
CatId CatName -------------------- -------------------- 1 Brush 2 Scarcat 3 New Flutter 267244677462397326 Scratchy 9223372036854775807 Magnus
И така, Котките масата беше успешна. Забележете обаче, че новата стойност за автоматично нарастване е по-ниска от предишната стойност (няма друга опция).
Без да има друга колона за записване на датата/часа, когато редът е бил вмъкнат/актуализиран, може да се предположи погрешно, че Магнус беше вмъкнат след Scratchy .
Сега нека се опитаме да вмъкнем нов ред в Кучетата таблица:
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );
Резултат:
Error: database or disk is full
Така получаваме различен резултат от Котките таблица.
Получих тази грешка, защото най-големият възможен ROWID
вече се използва в таблицата и тъй като тази таблица е създадена с AUTOINCREMENT
ключова дума, няма да се върне и да търси неизползван ROWID
стойност.
SELECT * FROM Dogs;
Резултат:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 9223372036854775807 Maximus
Освен това ще продължа да получавам тази грешка, дори ако изтрия Maximus от таблицата (т.е. кучето с максимален ROWID
стойност).
Нека опитаме:
DELETE FROM Dogs WHERE DogId = 9223372036854775807;
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );
Резултат:
Error: database or disk is full
Така че не само получаваме грешка, но и изтрих Maximus :
SELECT * FROM Dogs;
Резултат:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff
Важно е да се отбележи, че това ще се случи дори ако сменя ROWID
стойност на по-ниска стойност. Фактът, че вече съм използвал ROWID от 9223372036854775807, означава, че AUTOINCREMENT
вече няма да се увеличава автоматично.
Това е така, защото AUTOINCREMENT
използва само стойности, които са поне една по-високи от всяка стойност, която някога е съществувала в същата таблица .
Оттук нататък, ако искам да продължа да вмъквам стойности в тази колона, ще трябва изрично да вмъкна стойността. Това предполага, че вече нямам 9223372036854775807 реда в таблицата.
Нека вмъкнем отново Максимус с по-нисък ROWID
и опитайте отново:
INSERT INTO Dogs VALUES ( 5, 'Maximus' );
SELECT * FROM Dogs;
Резултат:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 5 Maximus
Сега нека се опитаме да вмъкнем Lickable още веднъж с помощта на AUTOINCREMENT
:
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );
Резултат:
Error: database or disk is full
Така че, въпреки че изтрих реда, който съдържа максималния ROWID
стойност на 9223372036854775807, все още не ми позволява автоматично да увеличавам колоната.
Точно така е проектирана. Максималният ROWID
е бил преди това в тази таблица и така AUTOINCREMENT
няма да се увеличава автоматично отново в тази таблица.
Единственият начин да добавите нов ред към тази таблица е да вмъкнете ръчно ROWID
стойност.
INSERT INTO Dogs VALUES (6, 'Lickable');
SELECT * FROM Dogs;
Резултат:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 5 Maximus 6 Lickable