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

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

    SQLiteにはON CONFLICTがあります 制約の競合を処理する方法を指定できる句。 UNIQUEに適用されます 、NOT NULLCHECK 、およびPRIMARY KEY 制約(ただし、FOREIGN KEYは不可) 制約)。

    この句で使用できるオプションは5つあります。

    • ABORT
    • FAIL
    • IGNORE
    • REPLACE
    • ROLLBACK

    この記事では、これらの各オプションの例と説明を提供します。

    ON CONFLICT 句はCREATE TABLEで使用されます ステートメントですが、ON CONFLICTを置き換えることでデータを挿入または更新するときにも使用できます。 ORを使用 。

    テーブルを作成するとき

    前述のように、ON CONFLICTを使用できます テーブルを作成するとき、またはデータを挿入/更新するとき。

    ON CONFLICTの使用例を次に示します。 テーブルの作成時。

    CREATE TABLE Products( 
        ProductId INTEGER PRIMARY KEY, 
        ProductName NOT NULL ON CONFLICT IGNORE, 
        Price
    );

    ON CONFLICTを使用する場合 句では、処理する特定の制約に適用します。この場合、NOT NULLに句を追加しました 制約。

    この場合、IGNOREを指定しました 、つまり、制約違反がある場合、SQLiteはその行をスキップして、処理を続行します。

    ここで、NULLを挿入しようとすると 製品名に その行がスキップされる列。

    INSERT INTO Products VALUES 
      (1, 'Hammer', 9.99),
      (2, NULL, 1.49),
      (3, 'Saw', 11.34),
      (4, 'Wrench', 37.00),
      (5, 'Chisel', 23.00),
      (6, 'Bandage', 120.00);
    
    SELECT * FROM Products;

    結果:

    ProductId   ProductName  Price     
    ----------  -----------  ----------
    1           Hammer       9.99      
    3           Saw          11.34     
    4           Wrench       37.0      
    5           Chisel       23.0      
    6           Bandage      120.0     

    データを挿入する場合

    この句は、データを挿入および更新するときにも使用できます。違いは、ON CONFLICTを置き換えることです ORを使用 。

    実例を示すために、前のテーブルを削除して再度作成しますが、ON CONFLICTは使用しません 条項:

    DROP TABLE IF EXISTS Products;
    
    CREATE TABLE Products( 
        ProductId INTEGER PRIMARY KEY, 
        ProductName NOT NULL, 
        Price
    );

    次に、同じデータを挿入し、OR IGNOREを使用します 制約に違反する行をスキップします。

    INSERT OR IGNORE INTO Products VALUES 
      (1, 'Hammer', 9.99),
      (2, NULL, 1.49),
      (3, 'Saw', 11.34),
      (4, 'Wrench', 37.00),
      (5, 'Chisel', 23.00),
      (6, 'Bandage', 120.00);
    
    SELECT * FROM Products;

    結果:

    ProductId   ProductName  Price     
    ----------  -----------  ----------
    1           Hammer       9.99      
    3           Saw          11.34     
    4           Wrench       37.0      
    5           Chisel       23.0      
    6           Bandage      120.0     

    したがって、前の例と同じ結果が得られます。

    これらの例では、IGNOREを使用しました オプション。これは、この条項で考えられる5つのオプションの1つにすぎません。

    以下は、5つのオプションのそれぞれを使用した例です。

    中止

    このオプションは、SQLITE_CONSTRAINTエラーで現在のSQLステートメントを中止し、現在のSQLステートメントによって行われた変更をすべて取り消します。ただし、同じトランザクション内の以前のSQLステートメントによって引き起こされた変更は保持され、トランザクションはアクティブなままです。

    これがデフォルトの動作です。つまり、これは、ON CONFLICTを使用しない場合の制約違反中に発生することです。 条項。

    ABORTを指定するとどうなるかの例を次に示します。 。

    DELETE FROM Products;
    
    INSERT OR ABORT INTO Products VALUES 
      (1, 'Hammer', 9.99),
      (2, NULL, 1.49),
      (3, 'Saw', 11.34),
      (4, 'Wrench', 37.00),
      (5, 'Chisel', 23.00),
      (6, 'Bandage', 120.00);
    
    SELECT * FROM Products;

    結果:

     

    INSERTのため、結果は返されませんでした 操作が中止されたため、テーブルは空になります。

    各行を独自のINSERTに配置するとどうなりますか。 トランザクション内のステートメント。

    BEGIN TRANSACTION;
    INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 9.99);
    INSERT OR ABORT INTO Products VALUES (2, NULL, 1.49);
    INSERT OR ABORT INTO Products VALUES (3, 'Saw', 11.34);
    INSERT OR ABORT INTO Products VALUES (4, 'Wrench', 37.00);
    INSERT OR ABORT INTO Products VALUES (5, 'Chisel', 23.00);
    INSERT OR ABORT INTO Products VALUES (6, 'Bandage', 120.00);
    COMMIT;
      
    SELECT * FROM Products;

    結果:

    ProductId   ProductName  Price     
    ----------  -----------  ----------
    1           Hammer       9.99      
    3           Saw          11.34     
    4           Wrench       37.0      
    5           Chisel       23.0      
    6           Bandage      120.0     

    失敗

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

    これが例です。

    DELETE FROM Products;
    
    INSERT OR FAIL INTO Products VALUES 
      (1, 'Hammer', 9.99),
      (2, NULL, 1.49),
      (3, 'Saw', 11.34),
      (4, 'Wrench', 37.00),
      (5, 'Chisel', 23.00),
      (6, 'Bandage', 120.00);
    
    SELECT * FROM Products;

    結果:

    ProductId   ProductName  Price     
    ----------  -----------  ----------
    1           Hammer       9.99      

    ここでは、個別のINSERTが含まれています トランザクション内のステートメント。

    DELETE FROM Products;
    
    BEGIN TRANSACTION;
    INSERT OR FAIL INTO Products VALUES (1, 'Hammer', 9.99);
    INSERT OR FAIL INTO Products VALUES (2, NULL, 1.49);
    INSERT OR FAIL INTO Products VALUES (3, 'Saw', 11.34);
    INSERT OR FAIL INTO Products VALUES (4, 'Wrench', 37.00);
    INSERT OR FAIL INTO Products VALUES (5, 'Chisel', 23.00);
    INSERT OR FAIL INTO Products VALUES (6, 'Bandage', 120.00);
    COMMIT;
      
    SELECT * FROM Products;

    結果:

    ProductId   ProductName  Price     
    ----------  -----------  ----------
    1           Hammer       9.99      
    3           Saw          11.34     
    4           Wrench       37.0      
    5           Chisel       23.0      
    6           Bandage      120.0     

    無視

    IGNORE オプションは、制約違反を含む1行をスキップし、何も問題がなかったかのようにSQLステートメントの後続の行の処理を続行します。制約違反を含む行の前後の他の行は、正常に挿入または更新されます。一意性についてエラーは返されません。NOT NULL 、およびUNIQUE このオプションを使用すると、制約エラーが発生します。ただし、このオプションはABORTのように機能します 外部キー制約エラーの場合。

    このページの最初の例では、IGNOREを使用しています 、しかしここに再びあります。

    DELETE FROM Products;
    
    INSERT OR IGNORE INTO Products VALUES 
      (1, 'Hammer', 9.99),
      (2, NULL, 1.49),
      (3, 'Saw', 11.34),
      (4, 'Wrench', 37.00),
      (5, 'Chisel', 23.00),
      (6, 'Bandage', 120.00);
    
    SELECT * FROM Products;

    結果:

    ProductId   ProductName  Price     
    ----------  -----------  ----------
    1           Hammer       9.99      
    3           Saw          11.34     
    4           Wrench       37.0      
    5           Chisel       23.0      
    6           Bandage      120.0     

    交換

    REPLACE オプションは違反に応じて動作が異なります:

    • UNIQUEの場合 またはPRIMARY KEY 制約違反が発生しました、、 REPLACE オプションは、現在の行を挿入または更新する前に、制約違反の原因となっている既存の行を削除し、コマンドは通常どおり実行を継続します。
    • NOT NULLの場合 制約違反が発生すると、NULLが置き換えられます その列のデフォルト値を持つ値、または列にデフォルト値がない場合は、ABORT アルゴリズムが使用されます。
    • CHECKの場合 制約または外部キー制約違反が発生した後、REPLACE ABORTのように機能します 。

    また、制約を満たすために行を削除する場合、再帰トリガーが有効になっている場合にのみ、削除トリガーが起動します。

    REPLACEを使用する例を次に示します。 オプション。

    DELETE FROM Products; 
    
    INSERT OR REPLACE INTO Products VALUES 
      (1, 'Hammer', 9.99),
      (2, 'Nails', 1.49),
      (3, 'Saw', 11.34),
      (1, 'Wrench', 37.00),
      (5, 'Chisel', 23.00),
      (6, 'Bandage', 120.00);
    
    SELECT * FROM Products;

    結果:

    ProductId   ProductName  Price     
    ----------  -----------  ----------
    1           Wrench       37.0      
    2           Nails        1.49      
    3           Saw          11.34     
    5           Chisel       23.0      
    6           Bandage      120.0     

    この例では、競合は主キーとの競合でした(同じ ProductIdで2つの行を挿入しようとしました )。 REPLACE オプションにより、2番目のものが最初のものに置き換わりました。

    ロールバック

    別のオプションは、ROLLBACKを使用することです 。

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

    複数のINSERT OR ROLLBACKを使用する例を次に示します。 トランザクション内のステートメント。

    DELETE FROM Products;
    
    BEGIN TRANSACTION;
    INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 9.99);
    INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49);
    INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34);
    INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00);
    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> DELETE FROM Products;
    sqlite> 
    sqlite> BEGIN TRANSACTION;
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 9.99);
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49);
    Error: NOT NULL constraint failed: Products.ProductName
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34);
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00);
    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     
    ----------  -----------  ----------
    3           Saw          11.34     
    4           Wrench       37.0      
    5           Chisel       23.0      
    6           Bandage      120.0     

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

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

    DELETE FROM Products;
    
    INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 9.99);
    INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49);
    INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34);
    INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00);
    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', 9.99);
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49);
    Error: NOT NULL constraint failed: Products.ProductName
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34);
    sqlite> INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00);
    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       9.99      
    3           Saw          11.34     
    4           Wrench       37.0      
    5           Chisel       23.0      
    6           Bandage      120.0     

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

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

    DELETE FROM Products;
    
    INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 9.99);
    INSERT OR ABORT INTO Products VALUES (2, NULL, 1.49);
    INSERT OR ABORT INTO Products VALUES (3, 'Saw', 11.34);
    INSERT OR ABORT INTO Products VALUES (4, 'Wrench', 37.00);
    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', 9.99);
    sqlite> INSERT OR ABORT INTO Products VALUES (2, NULL, 1.49);
    Error: NOT NULL constraint failed: Products.ProductName
    sqlite> INSERT OR ABORT INTO Products VALUES (3, 'Saw', 11.34);
    sqlite> INSERT OR ABORT INTO Products VALUES (4, 'Wrench', 37.00);
    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       9.99      
    3           Saw          11.34     
    4           Wrench       37.0      
    5           Chisel       23.0      
    6           Bandage      120.0     


    1. SQLiteの既存のテーブルに列を追加する

    2. SpringBootからHerokuPostgresに接続する

    3. Oracleで特定のテーブルがいつ作成されたかを確認するにはどうすればよいですか?

    4. SQLテーブル