SQLite 數據庫升級——新增字段處理總結

1、場景

在工做中,因爲新需求老是不斷,咱們常常會遇到項目中的一些表的結構要改變,好比最多見的就是 新增字段 了。這裏我總結一下我遇到這種狀況時的處理方法,SQLite 也有一些坑,但願能幫到有一樣需求的朋友們。下面我是用的 fmdb 進行的數據庫操做,用原生或者其餘工具的升級思想也是同樣的。html

2、升級操做

用戶升級 app 時,當咱們判斷到舊項目的版本號(或者數據庫的單獨版本號)小於某個版本號時,就進行咱們的升級操做。python

一、新增普通字段

若是你要新增的是個普通字段,並非個 主鍵(後面會介紹什麼狀況下會新增主鍵),那就好辦了,操做很簡單,直接執行新增字段語句便可。sql

先複習一下 SQL新增字段 語句: alter table mydownload add column 'IsFree' varchar(100) default '1' 其中的 column 能夠省略,同時也能夠不給 default 默認值。數據庫

下面是判斷升級並進行新增操做的具體代碼:app

if (![dbPointer columnExists:@"LoginUserId" inTableWithName:@"mydownload"]) {
    // 若是不存在 LoginUserId 字段則執行添加 LoginUserId 語句,默認值是當前登陸的用戶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 是個閹割的數據庫,有不少數據庫操做語句都是不支持的,好比不支持 批量增長字段,因此若是你要新增多個字段,那也只能一個一個的加了。工具

二、新增、修改主鍵或刪除某字段

若是你新增的是個 主鍵。好比你想在之前的文章 id 爲主鍵的的基礎上,再新增一個用戶 id,把文章 id 和用戶 id 做爲 聯合主鍵,那此時就不能執行新增字段方法了,也是由於 SQLite 的限制,ui

⚠️ 注意: SQLite 限制了 ALTER TABLE 的部分功能,只能將列添加到表的末尾或更改表的名稱。 若是要在表的結構中進行更復雜的更改,則必須 從新建立表。 您能夠將現有數據保存到臨時表,刪除舊錶,建立新表,而後從臨時表中複製數據。spa

例如,假設您有一個名爲「person」的表,其列名爲「id」,「name」和「age」,而且您要今後表中刪除列「age」。 如下 SQL 語句步驟說明了如何完成此操做:.net

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;
複製代碼

具體例子

下面再把我項目中具體的一個簡略例子展現出來供你們參考: 原表狀態: 原下載表 mydownload 只有兩個字段 EpisodeIdDownloaderFilePath,主鍵是 EpisodeId 。下載的東西不跟隨用戶。 新需求: 如今要求下載的東西跟隨用戶走,即下載列表只展現當前用戶下載的東西。這就須要新增一個 LoginUserId 用戶 id 字段,把它和 EpisodeId 做爲一個聯合主鍵,這樣下載的東西就能夠和用戶 id 綁定了。 具體代碼操做:code

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]) {
                    // 從舊數據表把舊數據插入新的數據表中
                    NSString *insertSql = [NSString stringWithFormat:@"INSERT INTO mydownload (EpisodeId,LoginUserId,DownloaderFilePath) select EpisodeId,'%@','1','',DownloaderFilePath from temp_mydownload", [Global sharedGlobal].loginInfo.userId];// 複製更名後的表到新建的表(注意:一列對應一列的進行復制,新增的字段能夠用''來補)
                    if ([dbPointer executeUpdate:insertSql]) {
                        [dbPointer executeUpdate:@"drop table temp_mydownload"];// 刪除舊錶
                        
                        [[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:@"hasModifyDownloadDatabase"];// 標記已經升級過下載表
                    };
                    
                }
            }
        } @catch (NSException *exception) {
            isRollBack = YES;
            // 事務回退
            [dbPointer rollback];
        } @finally {
            if (!isRollBack) {
                // 事務提交
                [dbPointer commit];
            }
        }
        
    }
複製代碼

以上的總結參考了並部分摘抄瞭如下文章,很是感謝如下做者的分享!:

一、《sqlite alter table添加多列》

二、《sqlite並不支持建表後修改主鍵,或刪除列,若是要修改,請參考以下作法》

三、《FMDB數據庫升級增長表字段》

轉載請備註原文出處,不得用於商業傳播——凡幾多

相關文章
相關標籤/搜索