SQLiteには、ON CONFLICT
と呼ばれる非標準のSQL拡張句があります。 これにより、制約の競合に対処する方法を指定できます。
特に、この句はUNIQUE
に適用されます 、NOT NULL
、CHECK
、および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