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

Come funziona AUTOINCREMENT in SQLite

In SQLite, un AUTOINCREMENT colonna è quella che utilizza un valore incrementato automaticamente per ogni riga inserita nella tabella.

Ci sono un paio di modi per creare un AUTOINCREMENT colonna:

  • Puoi crearlo in modo implicito quando definisci la colonna come INTEGER PRIMARY KEY .
  • Puoi crearlo esplicitamente con AUTOINCREMENT parola chiave. Uno svantaggio di questo metodo è che utilizza CPU, memoria, spazio su disco e sovraccarico di I/O su disco aggiuntivi.

Entrambi i metodi fanno sì che la colonna utilizzi un valore incrementale ogni volta che viene inserita una nuova riga con NULL in quella colonna.

Tuttavia, ci sono alcune sottili differenze nel funzionamento di ciascun metodo.

Senza la parola chiave AUTOINCREMENT

Quando dichiari una colonna come INTEGER PRIMARY KEY , aumenterà automaticamente. Pertanto, in realtà non è necessario utilizzare AUTOINCREMENT parola chiave per avere una colonna che utilizza un valore incrementale automaticamente per ogni riga.

Quando lo fai, qualsiasi NULL i valori vengono convertiti nel ROWID corrente . In altre parole, se inserisci NULL in quella colonna, verrà convertito nell'attuale ROWID .

In realtà, il modo in cui funziona è che la colonna diventa un alias per ROWID . Puoi accedere al ROWID valore utilizzando uno qualsiasi dei quattro nomi; il nome della colonna, ROWID , _ROWID_ o OID .

Un vantaggio dell'omissione di AUTOINCREMENT la parola chiave è che riduce il sovraccarico di CPU, memoria, spazio su disco e I/O del disco.

Un aspetto negativo importante, tuttavia, è che non puoi garantire che tutte le righe vengano incrementate in ordine crescente. Ciò è dovuto al modo in cui funziona l'incremento automatico quando si omette AUTOINCREMENT parola chiave rispetto all'utilizzo di quella parola chiave.

Quando ometti AUTOINCREMENT parola chiave, una volta ROWID è uguale al numero intero più grande possibile (9223372036854775807), SQLite proverà a trovare un ROWID positivo non utilizzato a caso.

Tuttavia, purché non utilizzi mai il massimo ROWID value e non elimini mai la voce nella tabella con il ROWID più grande , questo metodo genererà un ROWID univoco crescente s.

Con la parola chiave AUTOINCREMENT

Puoi anche creare colonne a incremento automatico in modo esplicito. Per fare ciò, usa il AUTOINCREMENT parola chiave.

Quando si utilizza questo metodo, viene utilizzato un algoritmo leggermente diverso per determinare il valore incrementato automaticamente.

Quando usi AUTOINCREMENT parola chiave, il ROWID scelto per la nuova riga è almeno uno più grande del ROWID più grande che ha mai prima esisteva in quella stessa tabella.

In altre parole, non tornerà indietro e riutilizzerà ROWID precedentemente cancellato valori. Una volta il più grande ROWID possibile è stato inserito, non sono consentiti nuovi inserimenti. Qualsiasi tentativo di inserire una nuova riga fallirà con un SQLITE_FULL errore.

Pertanto l'utilizzo di questo metodo garantisce che il ROWID s sono monotonicamente crescenti. In altre parole, puoi fare affidamento su questo metodo per avere ROWID s in ordine crescente.

Ciò non significa che i valori aumenteranno sempre di 1. Significa solo che non diminuiranno mai.

Esempio

Ecco un esempio per dimostrare la differenza tra la definizione implicita ed esplicita di una colonna con incremento automatico.

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;

Risultato iniziale:

CatId       CatName   
----------  ----------
1           Brush     
2           Scarcat   
3           Flutter  

DogId       DogName   
----------  ----------
1           Yelp      
2           Woofer    
3           Fluff      

Ora eliminiamo l'ultima riga di ogni tabella, inseriamo nuovamente le righe, quindi selezioniamo il risultato:

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;

Risultato:

CatId       CatName   
----------  ----------
1           Brush     
2           Scarcat   
3           New Flutter

DogId       DogName   
----------  ----------
1           Yelp      
2           Woofer    
4           New Fluff 

Per ricapitolare, i Gatti la tabella è stata creata senza il AUTOINCREMENT parola chiave e Cani la tabella è stata creata con il AUTOINCREMENT parola chiave.

Dopo aver eliminato l'ultima riga da Cats tabella, il successivo INSERT l'operazione ha prodotto lo stesso ROWID riutilizzato per quella riga.

Tuttavia, i Cani il tavolo era diverso. È stato creato con il AUTOINCREMENT parola chiave e quindi non può riutilizzare il valore precedente. Si incrementa semplicemente al valore successivo, lasciando uno spazio vuoto nella numerazione.

ROWID massimo

Possiamo fare un ulteriore passo avanti nell'esempio precedente e inserire una nuova riga utilizzando esplicitamente il massimo ROWID possibile.

INSERT INTO Cats VALUES ( 9223372036854775807, 'Magnus' );
INSERT INTO Dogs VALUES ( 9223372036854775807, 'Maximus' );

SELECT * FROM Cats;
SELECT * FROM Dogs;

Risultato:

CatId                 CatName             
--------------------  --------------------
1                     Brush               
2                     Scarcat             
3                     New Flutter         
9223372036854775807   Magnus              

DogId                 DogName             
--------------------  --------------------
1                     Yelp                
2                     Woofer              
4                     New Fluff           
9223372036854775807   Maximus             

OK, quindi entrambe le tabelle usano il numero intero più grande possibile come ROWID più grande valori.

Vediamo cosa succede quando provo a inserire una nuova riga in ogni tabella (senza specificare esplicitamente un valore per le colonne a incremento automatico).

Inserisci nei Gatti tabella:

INSERT INTO Cats VALUES ( NULL, 'Scratchy' );
SELECT * FROM Cats;

Risultato:

CatId                 CatName             
--------------------  --------------------
1                     Brush               
2                     Scarcat             
3                     New Flutter         
267244677462397326    Scratchy            
9223372036854775807   Magnus              

Quindi i Gatti il tavolo ha avuto successo. Tuttavia, si noti che il nuovo valore di incremento automatico è inferiore al valore precedente (non ha altre opzioni).

Senza avere un'altra colonna per registrare la data/ora di inserimento/aggiornamento della riga, si potrebbe erroneamente presumere che Magnus è stato inserito dopo Scratchy .

Ora proviamo a inserire una nuova riga nei Cani tabella:

INSERT INTO Dogs VALUES ( NULL, 'Lickable' );

Risultato:

Error: database or disk is full

Quindi otteniamo un risultato diverso rispetto a Cats tabella.

Ho ricevuto questo errore perché il ROWID più grande possibile è già utilizzato nella tabella e poiché questa tabella è stata creata con AUTOINCREMENT parola chiave, non tornerà indietro e cercherà un ROWID inutilizzato valore.

SELECT * FROM Dogs;

Risultato:

DogId                 DogName             
--------------------  --------------------
1                     Yelp                
2                     Woofer              
4                     New Fluff           
9223372036854775807   Maximus             

Inoltre, continuerò a ricevere questo errore, anche se elimino Maximus dalla tabella (ovvero il cane con il massimo ROWID valore).

Proviamolo:

DELETE FROM Dogs WHERE DogId = 9223372036854775807;
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );

Risultato:

Error: database or disk is full

Quindi non solo riceviamo un errore, ma ho anche eliminato Maximus :

SELECT * FROM Dogs;

Risultato:

DogId                 DogName             
--------------------  --------------------
1                     Yelp                
2                     Woofer              
4                     New Fluff           

È importante notare che ciò accadrà anche se cambio il ROWID valore a un valore inferiore. Il fatto che io abbia già utilizzato un ROWID di 9223372036854775807 significa che AUTOINCREMENT non aumenterà più automaticamente.

Questo perché AUTOINCREMENT Utilizza solo valori che sono almeno uno più alti di qualsiasi valore mai esistito in precedenza nella stessa tabella .

D'ora in poi, se volessi continuare a inserire valori in questa colonna, dovrei inserire esplicitamente il valore. Ciò presuppone che io non abbia già 9223372036854775807 righe nella tabella.

Reinseriamo Maximus con un ROWID inferiore e riprova:

INSERT INTO Dogs VALUES ( 5, 'Maximus' );
SELECT * FROM Dogs;

Risultato:

DogId                 DogName             
--------------------  --------------------
1                     Yelp                
2                     Woofer              
4                     New Fluff           
5                     Maximus            

Ora proviamo a inserire Lickable ancora una volta, utilizzando AUTOINCREMENT :

INSERT INTO Dogs VALUES ( NULL, 'Lickable' );

Risultato:

Error: database or disk is full

Quindi, anche se ho eliminato la riga che contiene il massimo ROWID valore di 9223372036854775807, ancora mi impedisce di incrementare automaticamente la colonna.

Questo è esattamente come è stato progettato. Il massimo ROWID è stato precedentemente in questa tabella e quindi AUTOINCREMENT non aumenterà di nuovo automaticamente in quella tabella.

L'unico modo per aggiungere una nuova riga a quella tabella è inserire manualmente il ROWID valore.

INSERT INTO Dogs VALUES (6, 'Lickable');
SELECT * FROM Dogs;

Risultato:

DogId                 DogName             
--------------------  --------------------
1                     Yelp                
2                     Woofer              
4                     New Fluff           
5                     Maximus             
6                     Lickable