sql >> Database teknologi >  >> RDS >> SQLite

Sådan fungerer AUTOINCREMENT i SQLite

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            


  1. AWS RDS:"SQLSTATE[22001] - Data for lange til kolonne" ved hjælp af MariaDB 10.2

  2. Løsning til:Gem opdatering, indsæt eller slet erklæring påvirkede et uventet antal rækker (0)

  3. Autonom transaktion i PostgreSQL 9.1

  4. PHP, ORM, MSSQL og Unicode, er det muligt at få disse til at fungere sammen?