我使用 SQLite 作為 iOS 應用程式的后端。我正面臨一個錯誤,即由于外鍵約束失敗而未執行特定的洗掉操作。盡管將罪魁禍首縮小到四種不同的外鍵約束,但我仍然不確定它是哪一種。SQLite 有沒有辦法告訴我是哪個特定的外鍵約束導致了錯誤?
uj5u.com熱心網友回復:
您始終可以使用查詢來預先檢查和確定沖突。類似的東西:-
CREATE TABLE IF NOT EXISTS parent (id INTEGER PRIMARY KEY,name TEXT);
INSERT INTO parent (name) VALUES ('parent1'),('parent2'),('parent3'),('parent4');
/* This being the pre-check query */
SELECT
2 IN (SELECT id FROM parent) AS FK1CHECK,
3 IN (SELECT id FROM parent) AS FK2CHECK,
10 IN (SELECT id FROM parent) AS FK3CHECK;
其中 2(存在)、3(存在)和 10(將??是 FK 沖突)
顯然,您將系結要檢查的 3 個引數/值,因此查詢將是:-
SELECT ? IN (SELECT id FROM parent) AS FK1CHECK, ? IN (SELECT id FROM parent) AS FK2CHECK, ? IN (SELECT id FROM parent) AS FK3CHECK;為簡單起見,只有 1 個父表,但會根據情況進行調整
結果 :-
1 1 0
即 F3CHECK,因為它是 0,表示會導致 FK 沖突
附加的
關于評論:-
我明白為什么第三個查詢會失敗,但我不明白為什么它會是外鍵約束的失敗。它只是一個不存在的記錄,您還沒有在此處定義任何外鍵約束。所以無論如何都不應該有任何外鍵約束失敗。努力想知道這與我的問題有什么關系
沒有 3 個查詢,它是通過 3 個子查詢輸出 3 列的單個查詢,每個查詢都指示關系是否有效。也就是說,它正在有效地執行 FK 約束會做的事情。
當您正在努力理解時,下面將逐步演示:-
/* drop the demo tables if they already exist */
DROP TABLE IF EXISTS child1;
DROP TABLE IF EXISTS child2;
DROP TABLE IF EXISTS child3;
DROP TABLE IF EXISTS parent;
/* turn on Foreign Key Support */
PRAGMA foreign_keys = ON;
/* Show the Foreign Key Support status */
PRAGMA foreign_keys;
/* create the parent table which will be a parent to 3 child tables */
CREATE TABLE IF NOT EXISTS parent (id INTEGER PRIMARY KEY, name TEXT);
/* create the 3 child tables with a Foreign Key constraint */
CREATE TABLE IF NOT EXISTS child1 (id INTEGER PRIMARY KEY, parentid INTEGER REFERENCES parent(id));
CREATE TABLE IF NOT EXISTS child2 (id INTEGER PRIMARY KEY, parentid INTEGER REFERENCES parent(id));
CREATE TABLE IF NOT EXISTS child3 (id INTEGER PRIMARY KEY, parentid INTEGER REFERENCES parent(id));
/* Add some parent rows */
INSERT INTO parent VALUES (1,'P1'),(2,'P2'),(3,'P3');
/* Attempt to insert three rows
child1 row with relationship to parent P1 (i.e. parentid = 1),
child2 with relationship to P2 (i.e. parentid = 2) and
child3 with relationship to P3 (i.e. parentid = 3)
but first PRE CHECK
*/
/* THE PRECHECK */
SELECT (SELECT 1 /*parentid value for child1 insert*/ IN (SELECT id FROM parent)) AS check1,
(SELECT 2 /* parentid value for child2 insert */ IN (SELECT id FROM parent)) AS check2,
(SELECT 3 /* parentid value for child3 insert */ IN (SELECT id FROM parent)) AS check3
;
/* This results in 1,1,1 i.e. ok to insert all three*/ :-
/* The the inserts */
INSERT INTO child1 (parentid) VALUES(1 /* parentid value for child1 insert*/);
INSERT INTO child2 (parentid) VALUES(2 /* parentid value for child2 insert*/);
INSERT INTO child3 (parentid) VALUES(3 /* parentid value for child3 insert*/);
/* Show the resultant data */
SELECT * FROM parent
LEFT JOIN child1 ON child1.parentid = parent.id
LEFT JOIN child2 ON child2.parentid = parent.id
LEFT JOIN child3 ON child3.parentid = parent.id
;
/* Attempt to insert three rows
child1 row with relationship to parent P2 (i.e. parentid = 1),
child2 with relationship to P3 (i.e. parentid = 2) and
child3 with relationship to non-existent (i.e. parentid = 3)
but first PRE CHECK
*/
SELECT (SELECT 2 /*parentid value for child1 insert*/ IN (SELECT id FROM parent)) AS check1,
(SELECT 3 /* parentid value for child2 insert */ IN (SELECT id FROM parent)) AS check2,
(SELECT 10 /* parentid value for child3 insert */ IN (SELECT id FROM parent)) AS check3
;
/* result will be 1,1,0 i.e. the 3rd insert will fail */
INSERT INTO child1 (parentid) VALUES(2 /* parentid value for child1 insert*/);
INSERT INTO child2 (parentid) VALUES(3 /* parentid value for child2 insert*/);
INSERT INTO child3 (parentid) VALUES(10 /* parentid value for child3 insert*/);
運行時,第一個結果來自 PRAGMA foreign_keys :-

- 即外鍵支持為真1,所以外鍵支持開啟
第二個結果是預檢查:-

- 由于 check1 是 1,那么第一次插入不會導致外鍵沖突/失敗。
- 當 check2 為 1 時,第二次插入不會導致外鍵沖突/失敗
- 當 check3 為 1 時,第三次插入不會導致外鍵沖突/失敗
插入后的第三個結果是查詢:-

即已插入相應的 child1/2/3 行。
第四個/最后一個是第二組插入物的預檢查:-

正如突出顯示的 check3 指示如果插入繼續,將發生外鍵沖突/失敗。結果可用于確定隨后的邏輯并確定哪個外鍵會導致沖突。
最后,由于上述是使用 SQLite 工具(Navicat)進行的,然后嘗試插入訊息:-
INSERT INTO child1 (parentid) VALUES(2 /* parentid value for child1 insert*/)
> Affected rows: 1
> Time: 0.083s
INSERT INTO child2 (parentid) VALUES(3 /* parentid value for child2 insert*/)
> Affected rows: 1
> Time: 0.074s
INSERT INTO child3 (parentid) VALUES(10 /* parentid value for child3 insert*/)
> FOREIGN KEY constraint failed
> Time: 0s
即由預檢查決定(check3 為 0),嘗試插入 child3 失敗并出現預測結果。
當然,上面的內容必須要量身定制。如果提供更具體的細節,本可以給出更具體的答案。
uj5u.com熱心網友回復:
據我所知,無法直接從 SQLite 獲取引發錯誤的特定外鍵約束。
為了除錯目的,您可以通過運行以下命令來關閉外鍵約束檢查(默認情況下它們已關閉),以找到該約束:
PRAGMA foreign_keys = OFF;
然后運行您的代碼并插入違反約束的行(您不會收到任何錯誤)。
之后,運行:
SELECT * FROM pragma_foreign_key_check();
您將獲得一個由 4 列組成的結果集:table、rowid、parent和fkid違反外鍵約束的資料庫中任何表的行。
檢查檔案pragma_foreign_key_check()和我在類似問題中給出的答案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/311409.html
