V SQLite, AUTOINCREMENT
sloupec je ten, který používá automaticky zvýšenou hodnotu pro každý řádek, který je vložen do tabulky.
Existuje několik způsobů, jak vytvořit AUTOINCREMENT
sloupec:
- Můžete jej vytvořit implicitně, když sloupec definujete jako
INTEGER PRIMARY KEY
. - Můžete jej vytvořit explicitně pomocí
AUTOINCREMENT
klíčové slovo. Jednou nevýhodou této metody je, že využívá extra CPU, paměť, místo na disku a režii diskových I/O.
Obě metody způsobí, že sloupec použije zvyšující se hodnotu pokaždé, když je vložen nový řádek s NULL
v tom sloupci.
Mezi tím, jak jednotlivé metody fungují, však existují jemné rozdíly.
Bez klíčového slova AUTOINCREMENT
Když deklarujete sloupec jako INTEGER PRIMARY KEY
, automaticky se zvýší. Proto ve skutečnosti nemusíte používat AUTOINCREMENT
klíčové slovo, aby měl sloupec, který používá automaticky se zvyšující hodnotu pro každý řádek.
Když to uděláte, všechny NULL
hodnoty jsou převedeny na aktuální ROWID
. Jinými slovy, pokud vložíte NULL
do tohoto sloupce, bude převeden na aktuální ROWID
.
Ve skutečnosti to funguje tak, že sloupec se stane aliasem pro ROWID
. Máte přístup k ROWID
hodnotu pomocí kteréhokoli ze čtyř jmen; název sloupce ROWID
, _ROWID_
nebo OID
.
Jednou z výhod vynechání AUTOINCREMENT
klíčové slovo je, že snižuje CPU, paměť, místo na disku a režii I/O disku.
Důležitou nevýhodou však je, že nemůžete zaručit, že se všechny řádky budou zvyšovat ve vzestupném pořadí. Je to způsobeno tím, jak funguje automatické zvyšování při vynechání AUTOINCREMENT
klíčové slovo vs používání tohoto klíčového slova.
Když vynecháte AUTOINCREMENT
klíčové slovo, jednou ROWID
se rovná největšímu možnému celému číslu (9223372036854775807), SQLite se pokusí najít nepoužitý kladný ROWID
náhodně.
Pokud však nikdy nepoužijete maximální ROWID
hodnotu a nikdy neodstraníte záznam v tabulce s největším ROWID
, bude tato metoda generovat monotónně rostoucí unikátní ROWID
s.
S klíčovým slovem AUTOINCREMENT
Můžete také explicitně vytvořit automaticky se zvyšující sloupce. K tomu použijte AUTOINCREMENT
klíčové slovo.
Když použijete tuto metodu, použije se k určení automaticky zvýšené hodnoty mírně odlišný algoritmus.
Když použijete AUTOINCREMENT
klíčové slovo ROWID
vybraný pro nový řádek je alespoň o jeden větší než největší ROWID
který má kdy dříve existoval ve stejné tabulce.
Jinými slovy, nevrátí se a znovu nepoužije dříve smazaný ROWID
hodnoty. Jednou největší možný ROWID
byl vložen, nejsou povoleny žádné nové vložky. Jakýkoli pokus o vložení nového řádku selže s SQLITE_FULL
chyba.
Proto použití této metody zaručuje, že ROWID
s monotónně přibývají. Jinými slovy, na tuto metodu se můžete spolehnout, že budete mít ROWID
s ve vzestupném pořadí.
To však neznamená, že se hodnoty vždy zvýší o 1. Znamená to pouze, že se nikdy nesníží.
Příklad
Zde je příklad, který demonstruje rozdíl mezi implicitním a explicitním definováním sloupce automatického zvýšení.
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;
Počáteční výsledek:
CatId CatName ---------- ---------- 1 Brush 2 Scarcat 3 Flutter DogId DogName ---------- ---------- 1 Yelp 2 Woofer 3 Fluff
Nyní smažeme poslední řádek v každé tabulce, vložíme řádky znovu a vybereme výsledek:
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;
Výsledek:
CatId CatName ---------- ---------- 1 Brush 2 Scarcat 3 New Flutter DogId DogName ---------- ---------- 1 Yelp 2 Woofer 4 New Fluff
Pro rekapitulaci, Kočky tabulka byla vytvořena bez AUTOINCREMENT
klíčové slovo a Psi tabulka byla vytvořena pomocí AUTOINCREMENT
klíčové slovo.
Po smazání posledního řádku z Kočky tabulka, další INSERT
operace vedla ke stejnému ROWID
znovu použit pro daný řádek.
Nicméně Psi stůl byl jiný. Byl vytvořen pomocí AUTOINCREMENT
klíčové slovo, a proto nemůže znovu použít předchozí hodnotu. Jednoduše se zvýší na další hodnotu, přičemž v číslování zůstane mezera.
Maximální ROWID
Předchozí příklad můžeme udělat o krok dále a vložit nový řádek explicitním použitím maximálního ROWID
možné.
INSERT INTO Cats VALUES ( 9223372036854775807, 'Magnus' );
INSERT INTO Dogs VALUES ( 9223372036854775807, 'Maximus' );
SELECT * FROM Cats;
SELECT * FROM Dogs;
Výsledek:
CatId CatName -------------------- -------------------- 1 Brush 2 Scarcat 3 New Flutter 9223372036854775807 Magnus DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 9223372036854775807 Maximus
Dobře, takže obě tabulky používají největší možné celé číslo jako největší ROWID
hodnoty.
Podívejme se, co se stane, když se pokusím vložit nový řádek do každé tabulky (bez explicitního zadání hodnoty pro automaticky se zvyšující sloupce).
Vložte do Kočky tabulka:
INSERT INTO Cats VALUES ( NULL, 'Scratchy' );
SELECT * FROM Cats;
Výsledek:
CatId CatName -------------------- -------------------- 1 Brush 2 Scarcat 3 New Flutter 267244677462397326 Scratchy 9223372036854775807 Magnus
Takže Kočky tabulka byla úspěšná. Všimněte si však, že nová hodnota automatického zvýšení je nižší než předchozí hodnota (nemá jinou možnost).
Bez dalšího sloupce pro záznam data/času, kdy byl řádek vložen/aktualizován, by se dalo nesprávně předpokládat, že Magnus byl vložen za Scratchy .
Nyní se pokusíme vložit nový řádek do Psi tabulka:
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );
Výsledek:
Error: database or disk is full
Dostaneme tedy jiný výsledek než Kočky tabulka.
Dostal jsem tuto chybu, protože největší možný ROWID
se již v tabulce používá, a protože tato tabulka byla vytvořena pomocí AUTOINCREMENT
klíčové slovo, nevrátí se a nebude hledat nepoužitý ROWID
hodnotu.
SELECT * FROM Dogs;
Výsledek:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 9223372036854775807 Maximus
Navíc se mi tato chyba bude zobrazovat i nadále, i když smažu Maximus ze stolu (tj. pes s maximálním ROWID
hodnota).
Zkusme to:
DELETE FROM Dogs WHERE DogId = 9223372036854775807;
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );
Výsledek:
Error: database or disk is full
Nejenže se nám zobrazí chyba, ale také jsem smazal Maximus :
SELECT * FROM Dogs;
Výsledek:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff
Je důležité si uvědomit, že k tomu dojde, i když změním ROWID
hodnotu na nižší hodnotu. Skutečnost, že jsem již použil ROWID 9223372036854775807, znamená, že AUTOINCREMENT
se již nebude automaticky zvyšovat.
Důvodem je AUTOINCREMENT
používá pouze hodnoty, které jsou alespoň o jednu vyšší než jakákoliv hodnota, která kdy v téže tabulce existovala .
Od této chvíle, pokud bych chtěl i nadále vkládat hodnoty do tohoto sloupce, musel bych hodnotu vkládat explicitně. To předpokládá, že v tabulce již nemám 9223372036854775807 řádků.
Znovu vložíme Maximus s nižším ROWID
a zkuste to znovu:
INSERT INTO Dogs VALUES ( 5, 'Maximus' );
SELECT * FROM Dogs;
Výsledek:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 5 Maximus
Nyní zkusme vložit Lickable ještě jednou pomocí AUTOINCREMENT
:
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );
Výsledek:
Error: database or disk is full
Takže i když jsem smazal řádek, který obsahuje maximální ROWID
hodnota 9223372036854775807, stále mi brání v automatickém zvyšování sloupce.
Přesně tak to bylo navrženo. Maximální ROWID
byl dříve v této tabulce, a tak AUTOINCREMENT
se v této tabulce automaticky znovu nezvýší.
Jediným způsobem, jak do tabulky přidat nový řádek, je ručně vložit ROWID
hodnotu.
INSERT INTO Dogs VALUES (6, 'Lickable');
SELECT * FROM Dogs;
Výsledek:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 5 Maximus 6 Lickable