Sqlite Foreign Key總結(jié)

android Sqlite 外鍵默認是關(guān)閉的,需要在SQLiteOpenHelper的子類里面打開,代碼如下

? @Override

public void onOpen(SQLiteDatabase db) {

? ? ? ? ? ?super.onOpen(db);

? ? ? ? ? ?if (!db.isReadOnly()) {

? ? ? ? ? ? // Enable foreign key constraints 開啟外鍵約束

? ? ? ? ? ?db.execSQL("PRAGMA foreign_keys=ON;");

? ?}

}


1介紹外鍵約束

SQL外鍵約束用于強制表之間的“存在”關(guān)系。例如,考慮使用以下SQL命令創(chuàng)建的數(shù)據(jù)庫模式

CREATE TABLE artist( artistid? ? INTEGER PRIMARY KEY, ?artistname? TEXT);

CREATE TABLE track(trackid? ? INTEGER,trackname? TEXT,trackartist INTEGER? ? -- Must map to an artist.artistid!);

使用此數(shù)據(jù)庫的應(yīng)用程序有權(quán)假定跟蹤表中的每一行都有一個對應(yīng)的行。畢竟,聲明中的評論是這樣說的。不幸的是,如果用戶使用外部工具編輯數(shù)據(jù)庫,或者應(yīng)用程序中存在bug,則行可能插入到不符合artist表中任何行的跟蹤表中?;蛘邚腶rtist表中刪除行,在track表中留下不符合artist中剩余行的孤立行。這可能導(dǎo)致應(yīng)用程序或應(yīng)用程序稍后出現(xiàn)故障,或者至少使應(yīng)用程序編碼更加困難。

一種解決方案是在數(shù)據(jù)庫模式中添加一個SQL外鍵約束,以強制artist和track之間的關(guān)系。為此,可以通過將track的聲明修改為以下來添加外鍵定義:

CREATE TABLE track(trackid? ? INTEGER,trackname? TEXT,trackartist INTEGER,

FOREIGN KEY(trackartist) REFERENCES artist(artistid));

通過這種方式,Sqlite被強制添加約束,當嘗試向track表插入一條和artist表中沒有關(guān)聯(lián)的數(shù)據(jù)時候會失敗.當從artist表中刪除一條和track表有關(guān)聯(lián)的數(shù)據(jù)會觸發(fā)異常(Foreign Key Constraint Exception).

sqlite> SELECT * FROM artist;

artistid ? ? ? artistname

--------? -----------------

1 ? ? ? ? ? ? ? ?Dean Martin

2 ? ? ? ? ? ? ? ?Frank Sinatra

sqlite> SELECT * FROM track;

trackid ? ? ? trackname? ? ? ? ? trackartist

-------? -----------------? -----------

11 ? ? ? ? ? ? ?That's Amore ? ? ? ? ? ? ?1

12 ? ? ? ? ? ? ?Christmas Blues ? ? ? ? 1

13 ? ? ? ? ? ? ? My Way ? ? ? ? ? ? ? ? ? ? ? 2


sqlite> INSERT INTO track VALUES(14, 'Mr. Bojangles', 3);

SQL error: foreign key constraint failed

//track表中trackartist=3有問題,track(trackartist) 關(guān)聯(lián)artist(artistid),artistid只有倆條數(shù)據(jù)

//(artistid=1和artistid=2) ,應(yīng)該首先給artist 插入一條artistid=3的數(shù)據(jù)就沒問題了.如下

INSERT INTO artist VALUES(3, 'Sammy Davis Jr.');

INSERT INTO track VALUES(14, 'Mr. Bojangles', 3);


正如所愿,不能通過刪除/更新artist表中和artist表有關(guān)聯(lián)的數(shù)據(jù)


DELETE FROM artist WHERE artistname = 'Frank Sinatra';

SQL error: foreign key constraint failed

artist表artistname = 'Frank Sinatra'這個數(shù)據(jù)和track表trackname = 'My Way'存在關(guān)聯(lián),不可以刪除,如果想刪除這條數(shù)據(jù)首先刪除track表中關(guān)聯(lián)的數(shù)據(jù),在執(zhí)行這個刪除命令即可如下。

DELETE FROM track WHERE trackname = 'My Way';

DELETE FROM artist WHERE artistname = 'Frank Sinatra';


UPDATE artist SET artistid=4 WHERE artistname = 'Dean Martin';

SQL error: foreign key constraint failed

artist表中artistname = 'Dean Martin'數(shù)據(jù)和track表有關(guān)聯(lián),如果想刪除,如下

DELETE FROM track WHERE trackname IN('That''s Amore', 'Christmas Blues');

UPDATE artist SET artistid=4 WHERE artistname = 'Dean Martin';


2.ON DELETE and ON UPDATE操作

外建On DeleteOn Update 有五種配置類型,No Action/Restrict/Set Null/Set Default/Cascade默認是No Action

no action. 父表刪除或者更新(外建所關(guān)聯(lián)的數(shù)據(jù)庫字段)時候,會報foreign key constrain錯誤.

restrict.和no action類似

set null.父表刪除或者更新(外建所關(guān)聯(lián)的數(shù)據(jù)庫字段)時候,子表foreign key關(guān)聯(lián)的列數(shù)據(jù)重置為null.

set default.與set null類似,父表刪除或者更新(外建所關(guān)聯(lián)的數(shù)據(jù)庫字段)時候,子表foreign key關(guān)聯(lián)的列數(shù)據(jù)重置為創(chuàng)建表時該列的default value.

cascade.父表與子表關(guān)聯(lián),刪除夫表會把子表里面與父表外建關(guān)聯(lián)的數(shù)據(jù)都刪除,更新父表里數(shù)據(jù)(被子表關(guān)聯(lián)的foreign key列)會同步更新子表外建列的值。

如下

CREATE TABLE artist(artistid? ? INTEGER PRIMARY KEY,artistname? TEXT);

CREATE TABLE track(trackid? ? INTEGER,trackname? TEXT,trackartist INTEGER REFERENCES artist(artistid) ON UPDATE CASCADE);


sqlite> SELECT * FROM artist;

artistid? ? ? artistname

--------? ? -----------------

1? ? ? ? ? ? ? ? Dean Martin

2? ? ? ? ? ? ? ? Frank Sinatra


sqlite> SELECT * FROM track;

trackid? ? ? ? trackname? ? ? ? ? ? trackartist

-------? ? ? --------------? ? ? ? -----------

11? ? ? ? ? ? ? ? That's Amore? ? ? ? ? ? ? 1

12? ? ? ? ? ? ? Christmas Blues? ? ? ? ? 1?

13? ? ? ? ? ? ? ? My Way? ? ? ? ? ? ? ? ? ? ? ? 2


//track表和artist表關(guān)聯(lián)外建使用ON UPDATE CASCADE,修改夫表,會同步修改子表所有與父表關(guān)聯(lián)列的值
sqlite> UPDATE artist SET artistid = 100 WHERE artistname = 'Dean Martin';

sqlite> SELECT * FROM artist;

artistid? artistname

--------? -----------------

2? ? ? ? Frank Sinatra

100? ? ? Dean Martin

sqlite> SELECT * FROM track;

trackid ? ? ? ?trackname? ? ? ? ? trackartist

------- ? ?-----------------? -----------

?11 ? ? ? ? ? ? ?That's Amore ? ? ? ? ?100

?12 ? ? ? ? ? ? ?Christmas Blues? ? 100

?13 ? ? ? ? ? ? ? ? ? ?My Way? ? ? ? ? ? 2


使用On Update或On Delete,如果配置ON DELETE SET DEFAULT,刪除夫表數(shù)據(jù)(與子表有關(guān)聯(lián)的數(shù)據(jù)),子表foreign key數(shù)據(jù)會重置為創(chuàng)建表時候default value.如果default value在夫表沒有關(guān)聯(lián),報foreign key constraint failed錯誤。如下

CREATE TABLE artist(artistid? ? INTEGER PRIMARY KEY,artistname? TEXT);

CREATE TABLE track(trackid? ? INTEGER,trackname? TEXT,trackartist INTEGER DEFAULT 0 REFERENCES artist(artistid) ON DELETE SET DEFAULT);

sqlite> SELECT * FROM artist;

artistid ? ? ? artistname

-------- ? ? -----------------

?3 ? ? ? ? ? ? ? ?Sammy Davis Jr.

sqlite> SELECT * FROM track;

trackid ? trackname? ? ? ? ? trackartist

------- ? --------------- ?-----------

?14 ? ? ? ? ?Mr. Bojangles ? ? ? ?3

//刪除父表數(shù)據(jù),子表trackartist=0,沒有與父表匹配報SQL error: foreign key constraint failed

sqlite> DELETE FROM artist WHERE artistname = 'Sammy Davis Jr.';

如下修改,在夫表插入一條default的數(shù)據(jù)即可

sqlite> INSERT INTO artist VALUES(0, 'Unknown Artist');

sqlite> DELETE FROM artist WHERE artistname = 'Sammy Davis Jr.';
































最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容