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

SQLiteにデータを挿入する際の主キーの競合への対処

    SQLiteには、ON CONFLICTと呼ばれる非標準のSQL拡張句があります。 これにより、制約の競合に対処する方法を指定できます。

    特に、この句はUNIQUEに適用されます 、NOT NULLCHECK 、およびPRIMARY KEY 制約。

    この記事では、この句を使用して主キー制約の競合を処理する方法を決定する方法の例を示します。

    「主キー制約の競合」とは、重複する値を主キー列に挿入しようとした場合を意味します。デフォルトでは、これを実行しようとすると、操作が中止され、SQLiteはエラーを返します。

    ただし、ON CONFLICTは使用できます SQLiteがこれらの状況に対処する方法を変更する句。

    1つのオプションは、CREATE TABLEでこの句を使用することです。 テーブルを作成するときのステートメント。そうすることで、すべてのINSERTがどのように決定されるかが決まります 操作が処理されます。

    もう1つのオプションは、INSERTの句を使用することです。 テーブルにデータを挿入しようとするときはいつでもステートメント。これにより、テーブルがそれを使用して作成されていない場合でも、句を利用できます。このオプションを使用する場合、構文は異なります。 ORを使用します ON CONFLICTの代わりに 。

    このページの例では、2番目のオプションを使用しています–テーブルをなしで作成します ON CONFLICT 句、代わりにORを指定します INSERTで ステートメント。

    サンプルテーブル

    簡単なテーブルを作成して、1つの行を追加しましょう。

    CREATE TABLE Products( 
        ProductId INTEGER PRIMARY KEY, 
        ProductName, 
        Price
    );
    
    INSERT INTO Products VALUES (1, 'Hammer', 8.00);
    
    SELECT * FROM Products;

    結果:

    ProductId   ProductName  Price     
    ----------  -----------  ----------
    1           Hammer       8.0       

    現在、 ProductIdの行が1つあります 1の 。

    これで、主キーの制約に違反するデータをテーブルに挿入するさまざまなシナリオを実行できます。

    例1-中止(デフォルトの動作)

    前述のように、SQLiteのデフォルトの動作は、INSERTを中止することです。 操作してエラーを返します。

    INSERT INTO Products VALUES (1, 'Wrench', 12.50);

    結果:

    Error: UNIQUE constraint failed: Products.ProductId

    エラーが返され、何も挿入されませんでした。

    これは、OR ABORTを使用するのと同じです オプション。

    INSERT OR ABORT INTO Products VALUES (1, 'Wrench', 12.50);

    結果:

    Error: UNIQUE constraint failed: Products.ProductId

    SELECTを実行すると、何も挿入されていないことを確認できます。 テーブルに対するステートメント。

    SELECT * FROM Products;

    結果:

    ProductId   ProductName  Price     
    ----------  -----------  ----------
    1           Hammer       8.0       

    テーブルには元の行のみが含まれていることがわかります。

    例2–無視

    1つの代替方法は、SQLiteに問題のある行を無視させることです。つまり、行をスキップして後続の行の処理を続行します。

    INSERT内でこれを行うには ステートメント、OR IGNOREを使用します 。

    この効果は、INSERT 操作は成功しますが、主キーの制約に違反する行はありません。

    INSERT OR IGNORE INTO Products VALUES 
      (1, 'Hammer', 12.00),
      (2, 'Nails', 2.50),
      (3, 'Saw', 10.50),
      (1, 'Wrench', 22.50),
      (5, 'Chisel', 23.00),
      (6, 'Bandage', 120.00);
    
    SELECT * FROM Products;

    結果:

    ProductId   ProductName  Price     
    ----------  -----------  ----------
    1           Hammer       8.0       
    2           Nails        2.5       
    3           Saw          10.5      
    5           Chisel       23.0      
    6           Bandage      120.0     

    この場合、テーブルにすでに存在するIDを持つ2つの新しい行を挿入しようとしたため、これらの行は両方ともスキップされました。

    例3–交換

    別のオプションは、元の行を新しい行に置き換えることです。

    つまり、既存のデータを新しいデータで上書きします。

    これを行うには、OR REPLACEを使用します 。

    INSERT OR REPLACE INTO Products VALUES 
      (1, 'Hammer', 12.00),
      (2, 'Nails', 2.50),
      (3, 'Saw', 10.50),
      (1, 'Wrench', 22.50),
      (5, 'Chisel', 23.00),
      (6, 'Bandage', 120.00);
    
    SELECT * FROM Products;

    結果:

    ProductId   ProductName  Price     
    ----------  -----------  ----------
    1           Wrench       22.5      
    2           Nails        2.5       
    3           Saw          10.5      
    5           Chisel       23.0      
    6           Bandage      120.0     

    この場合、ほとんどの行は同じであるため、INSERTの後に同じデータが含まれています 手術。ただし、最初の行が更新されて、INSERTの値を使用していることがわかります。 声明。

    また、2番目の値のセットを使用していることもわかります(2つが同じ ProductIdを共有しているように見えます 。

    つまり、効果はUPDATEのようなものです。 ステートメントとINSERT ステートメントを組み合わせました。

    例4–ロールバック

    もう1つのオプションは、ROLLBACKを使用することです。 オプション。

    これにより、SQLITE_CONSTRAINTエラーで現在のSQLステートメントが中止され、現在のトランザクションがロールバックされます。アクティブなトランザクションがない場合(すべてのコマンドで作成される暗黙のトランザクションを除く)、ABORTと同じように機能します。 アルゴリズム。

    このオプションがどのように機能するかに注意することは有益です。複数のINSERT OR ROLLBACKを使用する例を次に示します。 トランザクション内のステートメント。

    DELETE FROM Products;
    
    BEGIN TRANSACTION;
    INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 8.00);
    INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50);
    INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50);
    INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50);
    INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00);
    INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);
    COMMIT;
      
    SELECT * FROM Products;

    これを実行したときの端末からの完全な出力は次のとおりです。

    sqlite> BEGIN TRANSACTION;
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 8.00);
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50);
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50);
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50);
    Error: UNIQUE constraint failed: Products.ProductId
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00);
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);
    sqlite> COMMIT;
    Error: cannot commit - no transaction is active
    sqlite>   
    sqlite> SELECT * FROM Products;
    ProductId   ProductName  Price     
    ----------  -----------  ----------
    5           Chisel       23.0      
    6           Bandage      120.0     
    sqlite> 

    基本的に、ここで発生したのは、制約違反まで取得し、トランザクションをロールバックしたことです。次に、次の2行が処理され、次にCOMMIT キーワードが見つかりました。その時点で、トランザクションはすでにロールバックされていたため、アクティブなトランザクションがないことを示す別のエラーが発生しました。

    トランザクションから削除するとどうなりますか。

    DELETE FROM Products;
    
    INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 8.00);
    INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50);
    INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50);
    INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50);
    INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00);
    INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);
      
    SELECT * FROM Products;

    これを実行したときの端末からの完全な出力は次のとおりです。

    sqlite> DELETE FROM Products;
    sqlite> 
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 8.00);
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50);
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50);
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50);
    Error: UNIQUE constraint failed: Products.ProductId
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00);
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);
    sqlite>   
    sqlite> SELECT * FROM Products;
    ProductId   ProductName  Price     
    ----------  -----------  ----------
    1           Hammer       8.0       
    2           Nails        2.5       
    3           Saw          10.5      
    5           Chisel       23.0      
    6           Bandage      120.0     
    sqlite>

    この場合、ABORTのように機能しました 。

    これを示すために、ABORTを使用した同じステートメントを次に示します。 ROLLBACKの代わりに 。

    DELETE FROM Products;
    
    INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 8.00);
    INSERT OR ABORT INTO Products VALUES (2, 'Nails', 2.50);
    INSERT OR ABORT INTO Products VALUES (3, 'Saw', 10.50);
    INSERT OR ABORT INTO Products VALUES (1, 'Wrench', 22.50);
    INSERT OR ABORT INTO Products VALUES (5, 'Chisel', 23.00);
    INSERT OR ABORT INTO Products VALUES (6, 'Bandage', 120.00);
      
    SELECT * FROM Products;

    これを実行したときの端末からの完全な出力は次のとおりです。

    sqlite> DELETE FROM Products;
    sqlite> 
    sqlite> INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 8.00);
    sqlite> INSERT OR ABORT INTO Products VALUES (2, 'Nails', 2.50);
    sqlite> INSERT OR ABORT INTO Products VALUES (3, 'Saw', 10.50);
    sqlite> INSERT OR ABORT INTO Products VALUES (1, 'Wrench', 22.50);
    Error: UNIQUE constraint failed: Products.ProductId
    sqlite> INSERT OR ABORT INTO Products VALUES (5, 'Chisel', 23.00);
    sqlite> INSERT OR ABORT INTO Products VALUES (6, 'Bandage', 120.00);
    sqlite>   
    sqlite> SELECT * FROM Products;
    ProductId   ProductName  Price     
    ----------  -----------  ----------
    1           Hammer       8.0       
    2           Nails        2.5       
    3           Saw          10.5      
    5           Chisel       23.0      
    6           Bandage      120.0     
    sqlite> 

    失敗オプション

    FAIL オプションは、SQLITE_CONSTRAINTエラーで現在のSQLステートメントを中止します。ただし、このオプションは、失敗したSQLステートメントの以前の変更を取り消すことも、トランザクションを終了することもありません。

    DELETE FROM Products;
    
    INSERT OR FAIL INTO Products VALUES 
      (1, 'Hammer', 8.00),
      (2, 'Nails', 2.50),
      (3, 'Saw', 10.50),
      (1, 'Wrench', 22.50),
      (5, 'Chisel', 23.00),
      (6, 'Bandage', 120.00);
    
    SELECT * FROM Products;

    結果:

    ProductId   ProductName  Price     
    ----------  -----------  ----------
    1           Hammer       8.0       
    2           Nails        2.5       
    3           Saw          10.5      

    1. SQL Server 2016

    2. スキーマ名を省略した他のスキーマのテーブルを参照する

    3. 3つの簡単なSQLServerパフォーマンスの勝利

    4. Ubuntu 9.10(Karmic)でphpMyAdminを使用してMySQLを管理する