I SQLite, en AUTOINCREMENT
kolonne er en, der bruger en automatisk forøget værdi for hver række, der er indsat i tabellen.
Der er et par måder, hvorpå du kan oprette en AUTOINCREMENT
kolonne:
- Du kan oprette den implicit, når du definerer kolonnen som
INTEGER PRIMARY KEY
. - Du kan oprette det eksplicit med
AUTOINCREMENT
søgeord. En ulempe ved denne metode er, at den bruger ekstra CPU, hukommelse, diskplads og disk I/O-overhead.
Begge metoder får kolonnen til at bruge en stigende værdi hver gang en ny række indsættes med NULL
i den kolonne.
Der er dog nogle subtile forskelle mellem, hvordan hver metode virker.
Uden AUTOINCREMENT søgeordet
Når du erklærer en kolonne som INTEGER PRIMARY KEY
, vil den automatisk stige. Derfor behøver du faktisk ikke bruge AUTOINCREMENT
søgeord for at have en kolonne, der bruger en automatisk stigende værdi for hver række.
Når du gør dette, kan enhver NULL
værdier konverteres til den aktuelle ROWID
. Med andre ord, hvis du indsætter NULL
ind i den kolonne, vil den blive konverteret til den aktuelle ROWID
.
Den måde, det fungerer på, er, at kolonnen bliver et alias for ROWID
. Du kan få adgang til ROWID
værdi ved at bruge et af fire navne; kolonnenavnet, ROWID
, _ROWID_
eller OID
.
En fordel ved at udelade AUTOINCREMENT
nøgleordet er, at det reducerer CPU, hukommelse, diskplads og disk I/O-overhead.
En vigtig ulempe er dog, at du ikke kan garantere, at alle rækker vil blive øget i stigende rækkefølge. Dette skyldes den måde, automatisk inkrementering fungerer, når du udelader AUTOINCREMENT
søgeord i forhold til at bruge dette søgeord.
Når du udelader AUTOINCREMENT
søgeord én gang ROWID
er lig med det størst mulige heltal (9223372036854775807), vil SQLite forsøge at finde en ubrugt positiv ROWID
tilfældigt.
Men så længe du aldrig bruger den maksimale ROWID
værdi, og du sletter aldrig posten i tabellen med den største ROWID
, vil denne metode generere monotont stigende unikke ROWID
s.
Med AUTOINCREMENT-søgeordet
Du kan også oprette auto-inkrementerende kolonner eksplicit. For at gøre dette skal du bruge AUTOINCREMENT
søgeord.
Når du bruger denne metode, bruges en lidt anderledes algoritme til at bestemme den automatiske forøgede værdi.
Når du bruger AUTOINCREMENT
søgeord, ROWID
valgt til den nye række er mindst én større end den største ROWID
der har nogensinde før eksisterede i den samme tabel.
Med andre ord vil den ikke gå tilbage og genbruge tidligere slettede ROWID
værdier. Når den størst mulige ROWID
er blevet indsat, er ingen nye indstik tilladt. Ethvert forsøg på at indsætte en ny række vil mislykkes med en SQLITE_FULL
fejl.
Derfor garanterer brug af denne metode, at ROWID
s er monotont stigende. Med andre ord kan du stole på denne metode for at have ROWID
s i stigende rækkefølge.
Dette betyder dog ikke, at værdierne altid stiger med 1. Det betyder bare, at de aldrig vil falde.
Eksempel
Her er et eksempel for at demonstrere forskellen mellem implicit og eksplicit at definere en auto-increment-kolonne.
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;
Indledende resultat:
CatId CatName ---------- ---------- 1 Brush 2 Scarcat 3 Flutter DogId DogName ---------- ---------- 1 Yelp 2 Woofer 3 Fluff
Lad os nu slette den sidste række i hver tabel, indsætte rækkerne igen og derefter vælge resultatet:
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;
Resultat:
CatId CatName ---------- ---------- 1 Brush 2 Scarcat 3 New Flutter DogId DogName ---------- ---------- 1 Yelp 2 Woofer 4 New Fluff
For at opsummere, Katte tabel blev oprettet uden AUTOINCREMENT
søgeord og Hunde tabel blev oprettet med AUTOINCREMENT
søgeord.
Efter at have slettet den sidste række fra Katte tabel, den næste INSERT
operation resulterede i den samme ROWID
genbruges til den række.
Men Hundene bordet var anderledes. Den blev oprettet med AUTOINCREMENT
søgeord, og det kan derfor ikke genbruge den tidligere værdi. Den stiger ganske enkelt til den næste værdi og efterlader et hul i nummereringen.
Maksimal ROWID
Vi kan tage det forrige eksempel et skridt videre og indsætte en ny række ved eksplicit at bruge den maksimale ROWID
muligt.
INSERT INTO Cats VALUES ( 9223372036854775807, 'Magnus' );
INSERT INTO Dogs VALUES ( 9223372036854775807, 'Maximus' );
SELECT * FROM Cats;
SELECT * FROM Dogs;
Resultat:
CatId CatName -------------------- -------------------- 1 Brush 2 Scarcat 3 New Flutter 9223372036854775807 Magnus DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 9223372036854775807 Maximus
OK, så begge tabeller bruger det størst mulige heltal som deres største ROWID
værdier.
Lad os se, hvad der sker, når jeg forsøger at indsætte en ny række i hver tabel (uden eksplicit at angive en værdi for de automatiske stigningskolonner).
Indsæt i Katte tabel:
INSERT INTO Cats VALUES ( NULL, 'Scratchy' );
SELECT * FROM Cats;
Resultat:
CatId CatName -------------------- -------------------- 1 Brush 2 Scarcat 3 New Flutter 267244677462397326 Scratchy 9223372036854775807 Magnus
Altså Kattene tabellen var vellykket. Bemærk dog, at den nye automatiske stigningsværdi er lavere end den tidligere værdi (den har ingen anden mulighed).
Uden at have nogen anden kolonne til at registrere datoen/tidspunktet for, hvornår rækken blev indsat/opdateret, kan man fejlagtigt antage, at Magnus blev indsat efter Scratchy .
Lad os nu prøve at indsætte en ny række til Hunde tabel:
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );
Resultat:
Error: database or disk is full
Så vi får et andet resultat end Kattene tabel.
Jeg fik denne fejl, fordi den størst mulige ROWID
er allerede brugt i tabellen, og fordi denne tabel blev oprettet med AUTOINCREMENT
søgeord, vil det ikke gå tilbage og søge efter en ubrugt ROWID
værdi.
SELECT * FROM Dogs;
Resultat:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 9223372036854775807 Maximus
Desuden vil jeg fortsætte med at få denne fejl, selvom jeg sletter Maximus fra tabellen (dvs. hunden med den maksimale ROWID
værdi).
Lad os prøve det:
DELETE FROM Dogs WHERE DogId = 9223372036854775807;
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );
Resultat:
Error: database or disk is full
Så vi får ikke kun en fejl, men jeg har også slettet Maximus :
SELECT * FROM Dogs;
Resultat:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff
Det er vigtigt at bemærke, at dette vil ske, selvom jeg ændrer ROWID
værdi til en lavere værdi. Det faktum, at jeg allerede har brugt en ROWID på 9223372036854775807 betyder, at AUTOINCREMENT
vil ikke længere stige automatisk.
Dette er fordi AUTOINCREMENT
bruger kun værdier, der er mindst én højere end nogen værdi, der nogensinde før har eksisteret i den samme tabel .
Fra nu af, hvis jeg ville fortsætte med at indsætte værdier i denne kolonne, ville jeg være nødt til eksplicit at indsætte værdien. Dette forudsætter, at jeg ikke allerede har 9223372036854775807 rækker i tabellen.
Lad os genindsætte Maximus med en lavere ROWID
og prøv igen:
INSERT INTO Dogs VALUES ( 5, 'Maximus' );
SELECT * FROM Dogs;
Resultat:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 5 Maximus
Lad os nu prøve at indsætte Lickable igen ved at bruge AUTOINCREMENT
:
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );
Resultat:
Error: database or disk is full
Så selvom jeg har slettet den række, der indeholder den maksimale ROWID
værdi på 9223372036854775807, det stadig forhindrer mig i automatisk at øge kolonnen.
Det er præcis, hvordan det blev designet. Den maksimale ROWID
har tidligere været i denne tabel og derfor AUTOINCREMENT
vil ikke automatisk stige igen i den tabel.
Den eneste måde at tilføje en ny række til denne tabel på er manuelt at indsætte ROWID
værdi.
INSERT INTO Dogs VALUES (6, 'Lickable');
SELECT * FROM Dogs;
Resultat:
DogId DogName -------------------- -------------------- 1 Yelp 2 Woofer 4 New Fluff 5 Maximus 6 Lickable