android Sqlite 外鍵默認(rèn)是關(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外鍵約束用于強(qiáng)制表之間的“存在”關(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)假定跟蹤表中的每一行都有一個(gè)對(duì)應(yīng)的行厂画。畢竟睛约,聲明中的評(píng)論是這樣說的瑰步。不幸的是拐格,如果用戶使用外部工具編輯數(shù)據(jù)庫荐虐,或者應(yīng)用程序中存在bug藕夫,則行可能插入到不符合artist表中任何行的跟蹤表中嫡秕】视铮或者從artist表中刪除行,在track表中留下不符合artist中剩余行的孤立行淘菩。這可能導(dǎo)致應(yīng)用程序或應(yīng)用程序稍后出現(xiàn)故障遵班,或者至少使應(yīng)用程序編碼更加困難。
一種解決方案是在數(shù)據(jù)庫模式中添加一個(gè)SQL外鍵約束潮改,以強(qiáng)制artist和track之間的關(guān)系狭郑。為此,可以通過將track的聲明修改為以下來添加外鍵定義:
CREATE TABLE track(trackid? ? INTEGER,trackname? TEXT,trackartist INTEGER,
FOREIGN KEY(trackartist) REFERENCES artist(artistid));
通過這種方式,Sqlite被強(qiáng)制添加約束,當(dāng)嘗試向track表插入一條和artist表中沒有關(guān)聯(lián)的數(shù)據(jù)時(shí)候會(huì)失敗.當(dāng)從artist表中刪除一條和track表有關(guān)聯(lián)的數(shù)據(jù)會(huì)觸發(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'這個(gè)數(shù)據(jù)和track表trackname = 'My Way'存在關(guān)聯(lián),不可以刪除,如果想刪除這條數(shù)據(jù)首先刪除track表中關(guān)聯(lián)的數(shù)據(jù),在執(zhí)行這個(gè)刪除命令即可如下翰萨。
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 Delete和On Update 有五種配置類型,No Action/Restrict/Set Null/Set Default/Cascade默認(rèn)是No Action
no action. 父表刪除或者更新(外建所關(guān)聯(lián)的數(shù)據(jù)庫字段)時(shí)候,會(huì)報(bào)foreign key constrain錯(cuò)誤.
restrict.和no action類似
set null.父表刪除或者更新(外建所關(guān)聯(lián)的數(shù)據(jù)庫字段)時(shí)候,子表foreign key關(guān)聯(lián)的列數(shù)據(jù)重置為null.
set default.與set null類似,父表刪除或者更新(外建所關(guān)聯(lián)的數(shù)據(jù)庫字段)時(shí)候,子表foreign key關(guān)聯(lián)的列數(shù)據(jù)重置為創(chuàng)建表時(shí)該列的default value.
cascade.父表與子表關(guān)聯(lián),刪除夫表會(huì)把子表里面與父表外建關(guān)聯(lián)的數(shù)據(jù)都刪除,更新父表里數(shù)據(jù)(被子表關(guān)聯(lián)的foreign key列)會(huì)同步更新子表外建列的值糕殉。
如下
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,修改夫表,會(huì)同步修改子表所有與父表關(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ù)會(huì)重置為創(chuàng)建表時(shí)候default value.如果default value在夫表沒有關(guān)聯(lián),報(bào)foreign key constraint failed錯(cuò)誤亩鬼。如下
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,沒有與父表匹配報(bào)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.';