一、場景
在工作中,由于新需求總是不斷漓穿,我們經(jīng)常會遇到項目中的一些表的結(jié)構(gòu)要改變,比如最常見的就是 新增字段 了注盈。這里我總結(jié)一下我遇到這種情況時的處理方法,SQLite 也有一些坑叙赚,希望能幫到有同樣需求的朋友們老客。下面我是用的 fmdb 進行的數(shù)據(jù)庫操作,用原生或者其他工具的升級思想也是一樣的震叮。
二胧砰、升級操作
用戶升級 app 時,當(dāng)我們判斷到舊項目的版本號(或者數(shù)據(jù)庫的單獨版本號)小于某個版本號時苇瓣,就進行我們的升級操作尉间。
1、新增普通字段
如果你要新增的是個普通字段,并不是個 主鍵(后面會介紹什么情況下會新增主鍵)哲嘲,那就好辦了贪薪,操作很簡單,直接執(zhí)行新增字段語句即可眠副。
先復(fù)習(xí)一下 SQL 的 新增字段 語句:
alter table mydownload add column 'IsFree' varchar(100) default '1'
其中的 column 可以省略画切,同時也可以不給 default 默認(rèn)值。
下面是判斷升級并進行新增操作的具體代碼:
if (![dbPointer columnExists:@"LoginUserId" inTableWithName:@"mydownload"]) {
// 如果不存在 LoginUserId 字段則執(zhí)行添加 LoginUserId 語句囱怕,默認(rèn)值是當(dāng)前登錄的用戶id
NSString *addStr = [NSString stringWithFormat:@"alter table mydownload add column 'LoginUserId' varchar(100) default '%@'", [Global sharedGlobal].loginInfo.userId];
if ([dbPointer executeUpdate:addStr]){
DebugLog(@"添加 LoginUserId 字段成功霍弹!");
} else {
DebugLog(@"添加 LoginUserId 字段失敗娃弓!");
}
}
?? 注意:
這里要說一下典格,我們的 SQLite 是個閹割的數(shù)據(jù)庫,有很多數(shù)據(jù)庫操作語句都是不支持的台丛,比如不支持 批量增加字段耍缴,所以如果你要新增多個字段,那也只能一個一個的加了齐佳。
2私恬、新增、修改主鍵或刪除某字段
如果你新增的是個 主鍵炼吴。比如你想在以前的文章 id 為主鍵的的基礎(chǔ)上本鸣,再新增一個用戶 id,把文章 id 和用戶 id 作為 聯(lián)合主鍵硅蹦,那此時就不能執(zhí)行新增字段方法了荣德,也是因為 SQLite 的限制,
?? 注意:
SQLite 限制了 ALTER TABLE 的部分功能童芹,只能將列添加到表的末尾或更改表的名稱涮瞻。 如果要在表的結(jié)構(gòu)中進行更復(fù)雜的更改,則必須 重新創(chuàng)建表假褪。 您可以將現(xiàn)有數(shù)據(jù)保存到臨時表署咽,刪除舊表,創(chuàng)建新表生音,然后從臨時表中復(fù)制數(shù)據(jù)宁否。例如,假設(shè)您有一個名為“person”的表缀遍,其列名為“id”慕匠,“name”和“age”,并且您要從此表中刪除列“age”域醇。 以下 SQL 語句步驟說明了如何完成此操作:
BEGIN TRANSACTION; CREATE TEMPORARY TABLE person_backup(id,name); INSERT INTO person_backup SELECT id,name FROM person; DROP TABLE person; CREATE TABLE person(id,name); INSERT INTO person SELECT id,name FROM person_backup; DROP TABLE person_backup; COMMIT;
具體例子
下面再把我項目中具體的一個簡略例子展示出來供大家參考:
原表狀態(tài):
原下載表 mydownload 只有兩個字段 EpisodeId 和 DownloaderFilePath台谊,主鍵是 EpisodeId 蓉媳。下載的東西不跟隨用戶。
新需求:
現(xiàn)在要求下載的東西跟隨用戶走锅铅,即下載列表只展示當(dāng)前用戶下載的東西酪呻。這就需要新增一個 LoginUserId 用戶 id 字段,把它和 EpisodeId 作為一個聯(lián)合主鍵狠角,這樣下載的東西就可以和用戶 id 綁定了号杠。
具體代碼操作:
if (![dbPointer columnExists:@"LoginUserId" inTableWithName:@"mydownload"]) {
// 如果不存在 LoginUserId 字段則將原來的表改名
[dbPointer beginTransaction];
BOOL isRollBack = NO;
@try {
if ([dbPointer executeUpdate:@"ALTER TABLE mydownload RENAME TO temp_mydownload"]) {
NSString *executeStr = @"CREATE TABLE mydownload (EpisodeId varchar(100), LoginUserId varchar(100), DownloaderFilePath varchar(100),CONSTRAINT PK_mydownload PRIMARY KEY(EpisodeId,LoginUserId) )";
if ([dbPointer executeUpdate:executeStr]) {
// 從舊數(shù)據(jù)表把舊數(shù)據(jù)插入新的數(shù)據(jù)表中
NSString *insertSql = [NSString stringWithFormat:@"INSERT INTO mydownload (EpisodeId,LoginUserId,DownloaderFilePath) select EpisodeId,'%@','1','',DownloaderFilePath from temp_mydownload", [Global sharedGlobal].loginInfo.userId];// 復(fù)制改名后的表到新建的表(注意:一列對應(yīng)一列的進行復(fù)制,新增的字段可以用''來補)
if ([dbPointer executeUpdate:insertSql]) {
[dbPointer executeUpdate:@"drop table temp_mydownload"];// 刪除舊表
[[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:@"hasModifyDownloadDatabase"];// 標(biāo)記已經(jīng)升級過下載表
};
}
}
} @catch (NSException *exception) {
isRollBack = YES;
// 事務(wù)回退
[dbPointer rollback];
} @finally {
if (!isRollBack) {
// 事務(wù)提交
[dbPointer commit];
}
}
}
以上的總結(jié)參考了并部分摘抄了以下文章,非常感謝以下作者的分享7岣琛:
1姨蟋、《sqlite alter table添加多列》
2、《sqlite并不支持建表后修改主鍵立帖,或刪除列眼溶,如果要修改,請參考如下做法》
3晓勇、《FMDB數(shù)據(jù)庫升級增加表字段》
轉(zhuǎn)載請備注原文出處堂飞,不得用于商業(yè)傳播——凡幾多