sql >> データベース >  >> RDS >> SQLite

SQLiteでAUTOINCREMENTがどのように機能するか

    SQLiteでは、AUTOINCREMENT 列は、テーブルに挿入される行ごとに自動的にインクリメントされる値を使用する列です。

    AUTOINCREMENTを作成する方法はいくつかあります。 列:

    • 列をINTEGER PRIMARY KEYとして定義すると、暗黙的に作成できます。 。
    • AUTOINCREMENTを使用して明示的に作成できます キーワード。この方法の欠点の1つは、余分なCPU、メモリ、ディスクスペース、およびディスクI/Oオーバーヘッドを使用することです。

    どちらの方法でも、NULLで新しい行が挿入されるたびに、列は増分値を使用します。 その列に。

    ただし、各方法の動作には微妙な違いがあります。

    AUTOINCREMENTキーワードなし

    列をINTEGER PRIMARY KEYとして宣言する場合 、自動的にインクリメントします。したがって、実際にAUTOINCREMENTを使用する必要はありません。 キーワードを使用して、各行に自動的に増分する値を使用する列を作成します。

    これを行うと、NULL 値は現在のROWIDに変換されます 。つまり、NULLを挿入すると その列に、現在のROWIDに変換されます 。

    実際には、その動作方法は、列がROWIDのエイリアスになることです。 。 ROWIDにアクセスできます 4つの名前のいずれかを使用した値。列名、ROWID_ROWID_ 、またはOID

    AUTOINCREMENTを省略することの利点の1つ キーワードは、CPU、メモリ、ディスクスペース、およびディスクI/Oのオーバーヘッドを削減することです。

    ただし、重要な欠点は、すべての行が昇順でインクリメントされることを保証できないことです。これは、AUTOINCREMENTを省略した場合の自動インクリメントの仕組みによるものです。 キーワードとそのキーワードの使用。

    AUTOINCREMENTを省略した場合 キーワード、1回ROWID が可能な最大の整数(9223372036854775807)に等しい場合、SQLiteは未使用の正のROWIDを見つけようとします。 ランダムに。

    ただし、最大のROWIDを使用しない限り 値であり、最大のROWIDを持つテーブルのエントリを削除することはありません 、このメソッドは単調に増加する一意のROWIDを生成します s。

    AUTOINCREMENTキーワードを使用

    自動インクリメント列を明示的に作成することもできます。これを行うには、AUTOINCREMENTを使用します キーワード。

    この方法を使用する場合、自動インクリメント値を決定するためにわずかに異なるアルゴリズムが使用されます。

    AUTOINCREMENTを使用する場合 キーワード、ROWID 新しい行に選択されるのは、最大のROWIDより少なくとも1つ大きいです これまで 同じテーブルに存在する前。

    つまり、以前に削除したROWIDに戻って再利用することはありません。 値。かつては可能な限り最大のROWID が挿入されている場合、新しい挿入は許可されません。新しい行を挿入しようとすると、SQLITE_FULLで失敗します。 エラー。

    したがって、このメソッドを使用すると、ROWIDが保証されます。 sは単調に増加しています。つまり、ROWIDを持つためにこのメソッドに依存することができます s昇順。

    ただし、これは値が常に1ずつ増加するという意味ではありません。それは、それらが決して減少しないことを意味します。

    これは、自動インクリメント列を暗黙的に定義することと明示的に定義することの違いを示す例です。

    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;

    初期結果:

    CatId       CatName   
    ----------  ----------
    1           Brush     
    2           Scarcat   
    3           Flutter  
    
    DogId       DogName   
    ----------  ----------
    1           Yelp      
    2           Woofer    
    3           Fluff      

    次に、各テーブルの最後の行を削除し、行を再度挿入して、結果を選択します。

    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;

    結果:

    CatId       CatName   
    ----------  ----------
    1           Brush     
    2           Scarcat   
    3           New Flutter
    
    DogId       DogName   
    ----------  ----------
    1           Yelp      
    2           Woofer    
    4           New Fluff 

    要約すると、 テーブルはなしで作成されました AUTOINCREMENT キーワード、および テーブルは作成されました AUTOINCREMENT キーワード。

    から最後の行を削除した後 テーブル、次のINSERT 操作の結果、同じROWID その行に再利用されています。

    ただし、 テーブルが違いました。 AUTOINCREMENTで作成されました キーワードであるため、以前の値を再利用することはできません。単に次の値にインクリメントし、番号付けにギャップを残します。

    最大ROWID

    前の例をさらに一歩進めて、最大のROWIDを明示的に使用することにより、新しい行を挿入できます。 可能です。

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

    結果:

    CatId                 CatName             
    --------------------  --------------------
    1                     Brush               
    2                     Scarcat             
    3                     New Flutter         
    9223372036854775807   Magnus              
    
    DogId                 DogName             
    --------------------  --------------------
    1                     Yelp                
    2                     Woofer              
    4                     New Fluff           
    9223372036854775807   Maximus             

    OK、両方のテーブルが最大のROWIDとして可能な最大の整数を使用します 値。

    (自動インクリメント列の値を明示的に指定せずに)各テーブルに新しい行を挿入しようとするとどうなるか見てみましょう。

    に挿入します テーブル:

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

    結果:

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

    つまり、 テーブルは成功しました。ただし、新しい自動インクリメント値が以前の値よりも低いことに注意してください(他のオプションはありません)。

    行が挿入/更新された日付/時刻を記録する他の列がないと、 Magnusと誤って想定する可能性があります。 スクラッチの後に挿入されました 。

    それでは、に新しい行を挿入してみましょう。 テーブル:

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

    結果:

    Error: database or disk is full

    したがって、とは異なる結果が得られます テーブル。

    可能な限り最大のROWIDが原因で、このエラーが発生しました はすでにテーブルで使用されており、このテーブルはAUTOINCREMENTで作成されているためです。 キーワード、それは戻って未使用のROWIDを検索しません 値。

    SELECT * FROM Dogs;

    結果:

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

    さらに、 Maximus を削除しても、このエラーが引き続き発生します テーブルから(つまり、ROWIDが最大の犬 値)。

    試してみましょう:

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

    結果:

    Error: database or disk is full

    そのため、エラーが発生するだけでなく、 Maximusも削除しました :

    SELECT * FROM Dogs;

    結果:

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

    ROWIDを変更しても、これが発生することに注意してください。 値を低い値に。すでに9223372036854775807のROWIDを使用しているという事実は、AUTOINCREMENTを意味します。 自動的にインクリメントしなくなります。

    これは、AUTOINCREMENTが原因です 同じテーブルにこれまで存在した値よりも少なくとも1つ高い値のみを使用します

    今後、この列に値を挿入し続ける場合は、値を明示的に挿入する必要があります。これは、テーブルに9223372036854775807行がまだないことを前提としています。

    マキシマスを再挿入しましょう ROWIDを低くします もう一度やり直してください:

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

    結果:

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

    それでは、リック可能を挿入してみましょう。 もう一度、AUTOINCREMENTを使用します :

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

    結果:

    Error: database or disk is full

    したがって、最大のROWIDを含む行を削除しましたが 9223372036854775807の値、それはまだ 列を自動インクリメントできなくなります。

    これはまさにそれが設計された方法です。最大のROWID 以前はこのテーブルに含まれていたため、AUTOINCREMENT そのテーブルで自動的に再びインクリメントすることはありません。

    そのテーブルに新しい行を追加する唯一の方法は、ROWIDを手動で挿入することです。 値。

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

    結果:

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


    1. SQL Serverで「datetimeoffset」を「smalldatetime」に変換します(T-SQLの例)

    2. SQL Serverの一意のキーもインデックスですか?

    3. MariaDBでCOLLATION()がどのように機能するか

    4. MariaDBで特定の文字の前後のすべてを選択します