SQLiteにはON CONFLICT
があります 制約の競合を処理する方法を指定できる句。 UNIQUE
に適用されます 、NOT NULL
、CHECK
、および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