SQLite
 sql >> Base de Dados >  >> RDS >> SQLite

Como o AUTOINCREMENT funciona no SQLite


No SQLite, um AUTOINCREMENT coluna é aquela que usa um valor incrementado automaticamente para cada linha inserida na tabela.

Existem algumas maneiras de criar um AUTOINCREMENT coluna:
  • Você pode criá-lo implicitamente ao definir a coluna como INTEGER PRIMARY KEY .
  • Você pode criá-lo explicitamente com o AUTOINCREMENT palavra-chave. Uma desvantagem desse método é que ele usa CPU extra, memória, espaço em disco e sobrecarga de E/S de disco.

Ambos os métodos fazem com que a coluna use um valor de incremento cada vez que uma nova linha é inserida com NULL nessa coluna.

No entanto, existem algumas diferenças sutis entre como cada método funciona.

Sem a palavra-chave AUTOINCREMENT


Quando você declara uma coluna como INTEGER PRIMARY KEY , ele será incrementado automaticamente. Portanto, você não precisa usar o AUTOINCREMENT palavra-chave para ter uma coluna que usa um valor de incremento automático para cada linha.

Ao fazer isso, qualquer NULL os valores são convertidos no ROWID atual . Em outras palavras, se você inserir NULL nessa coluna, ela será convertida para o ROWID atual .

Na verdade, a forma como funciona é que a coluna se torna um alias para o ROWID . Você pode acessar o ROWID valor usando qualquer um dos quatro nomes; o nome da coluna, ROWID , _ROWID_ , ou OID .

Uma vantagem de omitir o AUTOINCREMENT palavra-chave é que ela reduz CPU, memória, espaço em disco e sobrecarga de E/S de disco.

Uma desvantagem importante, no entanto, é que você não pode garantir que todas as linhas serão incrementadas em ordem crescente. Isso se deve ao modo como o incremento automático funciona ao omitir o AUTOINCREMENT palavra-chave vs usando essa palavra-chave.

Quando você omite o AUTOINCREMENT palavra-chave, uma vez ROWID for igual ao maior inteiro possível (9223372036854775807), o SQLite tentará encontrar um ROWID positivo não utilizado aleatoriamente.

No entanto, contanto que você nunca use o máximo de ROWID valor e você nunca exclui a entrada na tabela com o maior ROWID , este método irá gerar um ROWID único monotonicamente crescente s.

Com a palavra-chave AUTOINCREMENT


Você também pode criar colunas de incremento automático explicitamente. Para fazer isso, use o AUTOINCREMENT palavra-chave.

Quando você usa esse método, um algoritmo ligeiramente diferente é usado para determinar o valor incrementado automaticamente.

Quando você usa o AUTOINCREMENT palavra-chave, o ROWID escolhido para a nova linha é pelo menos um maior que o maior ROWID que nunca antes existia nessa mesma tabela.

Em outras palavras, ele não voltará e reutilizará ROWID excluído anteriormente valores. Uma vez que o maior possível ROWID foi inserido, não são permitidas novas inserções. Qualquer tentativa de inserir uma nova linha falhará com um SQLITE_FULL erro.

Portanto, usar este método garante que o ROWID s são crescentes monotonicamente. Em outras palavras, você pode confiar neste método para ter ROWID s em ordem crescente.

Isso não significa que os valores sempre serão incrementados em 1. Significa apenas que eles nunca diminuirão.

Exemplo


Aqui está um exemplo para demonstrar a diferença entre definir implicitamente e explicitamente uma coluna de incremento automático.
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;

Resultado inicial:
CatId       CatName   
----------  ----------
1           Brush     
2           Scarcat   
3           Flutter  

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

Agora vamos excluir a última linha de cada tabela, inserir as linhas novamente e selecionar o resultado:
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;

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

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

Para recapitular, os Gatos a tabela foi criada sem o AUTOINCREMENT palavra-chave e Cães a tabela foi criada com o AUTOINCREMENT palavra-chave.

Depois de excluir a última linha de Gatos tabela, o próximo INSERT operação resultou no mesmo ROWID sendo reutilizado para essa linha.

No entanto, os Cães mesa era diferente. Ele foi criado com o AUTOINCREMENT palavra-chave e, portanto, não pode reutilizar o valor anterior. Ele simplesmente incrementa para o próximo valor, deixando uma lacuna na numeração.

ROWID máximo


Podemos levar o exemplo anterior um passo adiante e inserir uma nova linha usando explicitamente o máximo ROWID possível.
INSERT INTO Cats VALUES ( 9223372036854775807, 'Magnus' );
INSERT INTO Dogs VALUES ( 9223372036854775807, 'Maximus' );

SELECT * FROM Cats;
SELECT * FROM Dogs;

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

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

OK, então ambas as tabelas usam o maior inteiro possível como seu maior ROWID valores.

Vamos ver o que acontece quando tento inserir uma nova linha em cada tabela (sem especificar explicitamente um valor para as colunas de incremento automático).

Insira nos Gatos tabela:
INSERT INTO Cats VALUES ( NULL, 'Scratchy' );
SELECT * FROM Cats;

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

Então os Gatos mesa foi bem sucedida. No entanto, observe que o novo valor de incremento automático é menor que o valor anterior (não há outra opção).

Sem ter nenhuma outra coluna para registrar a data/hora em que a linha foi inserida/atualizada, pode-se supor incorretamente que Magnus foi inserido após Scratchy .

Agora vamos tentar inserir uma nova linha no Cães tabela:
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );

Resultado:
Error: database or disk is full

Assim, obtemos um resultado diferente dos Gatos tabela.

Recebi este erro porque o maior ROWID possível já está sendo usado na tabela, e porque esta tabela foi criada com o AUTOINCREMENT palavra-chave, ele não voltará e procurará um ROWID não utilizado valor.
SELECT * FROM Dogs;

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

Além disso, continuarei recebendo esse erro, mesmo se excluir Maximus da tabela (ou seja, o cão com o máximo de ROWID valor).

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

Resultado:
Error: database or disk is full

Portanto, não apenas recebemos um erro, mas também excluí Maximus :
SELECT * FROM Dogs;

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

É importante observar que isso acontecerá mesmo se eu alterar o ROWID valor para um valor inferior. O fato de eu já ter usado um ROWID de 9223372036854775807 significa que AUTOINCREMENT não será mais incrementado automaticamente.

Isso ocorre porque AUTOINCREMENT usa apenas valores que são pelo menos um valor mais alto do que qualquer valor que já existiu na mesma tabela .

A partir de agora, se eu quisesse continuar inserindo valores nessa coluna, precisaria inserir explicitamente o valor. Isso pressupõe que eu ainda não tenha 9223372036854775807 linhas na tabela.

Vamos reinserir o Maximus com um ROWID menor e tente novamente:
INSERT INTO Dogs VALUES ( 5, 'Maximus' );
SELECT * FROM Dogs;

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

Agora vamos tentar inserir Lickable mais uma vez, usando AUTOINCREMENT :
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );

Resultado:
Error: database or disk is full

Portanto, embora eu tenha excluído a linha que contém o máximo de ROWID valor de 9223372036854775807, ainda me impede de incrementar automaticamente a coluna.

É exatamente assim que foi projetado. O máximo de ROWID esteve anteriormente nesta tabela e, portanto, AUTOINCREMENT não será incrementado automaticamente novamente nessa tabela.

A única maneira de adicionar uma nova linha a essa tabela é inserir manualmente o ROWID valor.
INSERT INTO Dogs VALUES (6, 'Lickable');
SELECT * FROM Dogs;

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