iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 22
0
自我挑戰組

Android初學筆記系列 第 22

Day 22 - 更新SQLite資料庫

APP發展的過程中難免會更動資料欄位,若還在開發的話可以直接重新安裝解決,但若是已經上架發布的APP,則需在不影響使用的情況下更動欄位。

SQLite新增欄位沒問題,但不能對舊欄位做刪改,如欄位名稱、型態都不能改,當然也不能刪除。若真的需刪改舊欄位的話需做一些人工處理,今天就來看看新增及刪改舊資料表的方式。

新增資料表或欄位

操作步驟:

  1. 更新資料庫版本號,通常是加一
  2. 在onCreate()中建立資料表或欄位
  3. 在onUpgrade()中新增兩版本差異的部分

目標:在UserData增加一個Phone欄位,並新增一張CompanyData資料表

public class MyDBHelper extends SQLiteOpenHelper {

    // 略..
    
    // 資料庫版本
    private final static int _DBVersion = 2;    // 從1更新為2

    // 略..

    @Override
    public void onCreate(SQLiteDatabase db) {

        // 最新的UserData資料表
        db.execSQL("CREATE TABLE IF NOT EXISTS UserData ( " +
                "_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                "Name TEXT, " +
                "Age INTEGER, " +
                "Email TEXT DEFAULT '', " +
                "Phone TEXT " +
                ")");

        // 新增一張CompanyData資料表
        db.execSQL("CREATE TABLE IF NOT EXISTS CompanyData ( " +
                "_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                "Name TEXT, " +
                "Phone TEXT, " +
                "Address TEXT " +
                ")");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        if (newVersion > oldVersion) {

            db.beginTransaction();
            boolean success = false;

            // 依照舊的版本做相應的更新
            switch (oldVersion) {
                case 1:
                    // 在UserData加上Phone欄位
                    db.execSQL("ALTER TABLE UserData ADD COLUMN Phone TEXT");

                    // 新增一張CompanyData資料表
                    db.execSQL("CREATE TABLE IF NOT EXISTS CompanyData ( " +
                            "_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                            "Name TEXT, " +
                            "Phone TEXT, " +
                            "Address TEXT " +
                            ")");

                    success = true;
                    break;
            }
            if (success) {
                db.setTransactionSuccessful();
            }
            db.endTransaction();
        }
        else {
            onCreate(db);
        }
    }
}

在onCreate()建立新的資料表是為了讓新安裝的用戶直接有完整資料表,而在onUpgrade()裡的部分則是為舊用戶升級APP時所準備

執行APP並用Stetho看資料庫就會看到新的資料表和欄位
http://ithelp.ithome.com.tw/upload/images/20170106/20103849sHN1KS3CZC.png


刪改舊欄位

SQLite不能變更舊的資料表欄位,若真的需要修改時最簡單的方式是將舊的資料表刪掉重新創過,此方法有個致命的缺點是會將使用者的資料刪除,須非常謹慎使用

操作步驟:

  1. 更新資料庫版本號
  2. Drop刪掉舊資料表
  3. 建立新的資料表

目標:刪除UserData的email欄位以及將Phone重新命名為Tex,我們將資料庫更新到版本3,並用Drop刪掉舊資料表再重新創過

public class MyDBHelper extends SQLiteOpenHelper {

    // 略..
    
    // 資料庫版本
    private final static int _DBVersion = 3; // 1. 更新資料庫版本號,從2更新到3

    // 略..
    
    @Override
    public void onCreate(SQLiteDatabase db) {

        // 修改UserData至最新狀態
        db.execSQL("CREATE TABLE IF NOT EXISTS UserData ( " +
                "_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                "Name TEXT, " +
                "Age INTEGER, " +
                "Tex TEXT " +
                ")");

        // 略..
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        if (newVersion > oldVersion) {

            db.beginTransaction();
            boolean success = false;

            //由之前不用的版本,可做不同的動作
            switch (oldVersion) {
                case 1:

                    // 略..

                case 2:
                    // 2. 刪掉UserData資料表
                    db.execSQL("DROP TABLE UserData ");
                    // 3. 建立新的UserData
                    db.execSQL("CREATE TABLE IF NOT EXISTS UserData ( " +
                            "_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                            "Name TEXT, " +
                            "Age INTEGER, " +
                            "Tex TEXT " +
                            ")");

                    success = true;
                    break;    // 注意要到最後一個case才break
            }
            // 略..
}

當更新多個版本時需在最後一個case才使用break,以免case 1更新完就break而沒有更新到case 2的內容

執行結果
http://ithelp.ithome.com.tw/upload/images/20170106/20103849Eq6ImelBeb.png

刪改舊欄位並保留資料

前述方法的缺點是會將已儲存的資料刪除,所以我們可以人工將舊資料留下來,等新資料表創好再把資料轉過去,就可以有新的資料表且保留舊的資料

先隨便新增一筆資料到UserData以便測試

// 將要新增的資料放到ContentValues
ContentValues values = new ContentValues();
values.put("Name", "Ivan");
values.put("Age", 18);
values.put("Tex", "0987-654-321");
// 新增資料到UserData欄位
db.insert("UserData", null, values);

操作步驟:

  1. 更新資料庫版本號
  2. 將舊資料表重新命名
  3. 建立新資料表
  4. 將舊資料insert到新的資料表
  5. 刪除舊資料表

目標:刪除UserData裡的Age欄位,但要保留Name和Tex的內容

public class MyDBHelper extends SQLiteOpenHelper {

    // 資料庫版本
    private final static int _DBVersion = 4; //  1. 從版本3更新到4

    // 略..

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        if (newVersion > oldVersion) {

            db.beginTransaction();
            boolean success = false;

            switch (oldVersion) {
                case 1:
                    // 略..

                case 2:
                    // 略..

                case 3:
                    // 2. 將舊資料表重新命名
                    db.execSQL("ALTER TABLE UserData RENAME TO UserData_temp");
                    // 3. 建立新資料表
                    db.execSQL("CREATE TABLE IF NOT EXISTS UserData ( " +
                            "_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                            "Name TEXT, " +
                            "Tex TEXT " +
                            ")");
                    // 4. 將舊資料insert到新的資料表
                    db.execSQL("INSERT INTO UserData (Name, Tex) " +
                            "SELECT Name, Tex " +
                            "FROM UserData_temp");
                    // 5. 刪除舊資料表
                    db.execSQL("DROP TABLE UserData_temp ");

                    success = true;
                    break;
            }
            // 略..
}

若剛有在Activity中新增測試資料記得先移除該段落,執行結果:
http://ithelp.ithome.com.tw/upload/images/20170106/20103849R3yeJvw2ZJ.png


以上就是更新SQLite資料庫的部分,大致須注意的是每次更新要改版本號和onCreate()裡要放最新的資料表,而onUpgrade時對舊資料的處理則是依需求而定,都是不需要的資料可以直接Drop掉,若要保留資料則用temp的方式更新。


上一篇
Day 21 - SQLite資料庫 & 測試工具Stetho
下一篇
Day 23 - OkHttp網路連線
系列文
Android初學筆記30

尚未有邦友留言

立即登入留言