APP發展的過程中難免會更動資料欄位,若還在開發的話可以直接重新安裝解決,但若是已經上架發布的APP,則需在不影響使用的情況下更動欄位。
SQLite新增欄位沒問題,但不能對舊欄位做刪改,如欄位名稱、型態都不能改,當然也不能刪除。若真的需刪改舊欄位的話需做一些人工處理,今天就來看看新增及刪改舊資料表的方式。
操作步驟:
目標:在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看資料庫就會看到新的資料表和欄位
SQLite不能變更舊的資料表欄位,若真的需要修改時最簡單的方式是將舊的資料表刪掉重新創過,此方法有個致命的缺點是會將使用者的資料刪除,須非常謹慎使用
操作步驟:
目標:刪除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的內容
執行結果
前述方法的缺點是會將已儲存的資料刪除,所以我們可以人工將舊資料留下來,等新資料表創好再把資料轉過去,就可以有新的資料表且保留舊的資料
先隨便新增一筆資料到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);
操作步驟:
目標:刪除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中新增測試資料記得先移除該段落,執行結果:
以上就是更新SQLite資料庫的部分,大致須注意的是每次更新要改版本號和onCreate()裡要放最新的資料表,而onUpgrade時對舊資料的處理則是依需求而定,都是不需要的資料可以直接Drop掉,若要保留資料則用temp的方式更新。