2010-08-06 65 views
13

我收到一個錯誤Logcat說某個列(在我的SQLiteOpenHelper子類)不存在。我想我可以通過更改DATABASE_CREATE字符串來升級數據庫。但顯然不是,我怎麼能(逐步)將我的SQLite數據庫從版本1升級到版本2?將SQLite數據庫從一個版本升級到另一個版本?

我很抱歉,如果問題似乎「不好」,但我仍然在學習Android。

@ Pentium10這是我做onUpgrade:

private static final int DATABASE_VERSION = 1; 

.... 

switch (upgradeVersion) { 
case 1: 
    db.execSQL("ALTER TABLE task ADD body TEXT"); 
    upgradeVersion = 2; 
    break; 
} 

... 
+0

另請參見https://stackoverflow.com/questions/8133597/android-upgrading-db-version-and-adding-new-table – Suragch 2018-02-26 07:32:54

回答

46

好吧,你遇到了更大的問題之前,你應該知道,SQLite是在ALTER TABLE命令的限制,它允許addrename唯一沒有remove/drop,這是通過表格的重新創建完成的。

您應始終擁有新的表創建查詢,並將其用於升級並傳輸任何現有數據。注意:onUpgrade方法爲你的sqlite幫助對象運行一個,你需要處理它中的所有表。

所以建議採取什麼onUpgrade:

  • 的BeginTransaction
  • 運行與if not exists表生成(我們正在做的升級,因此該表可能還不存在,它將無法修改和刪除)
  • 放在一個列表中的現有列List<String> columns = DBUtils.GetColumns(db, TableName);
  • 備份表(ALTER table " + TableName + " RENAME TO 'temp_" + TableName
  • 創建新表(最新表創建小號CHEMA)
  • 獲得與新列的交叉點,從升級後的表採取這一時間列(columns.retainAll(DBUtils.GetColumns(db, TableName));
  • 恢復數據(String cols = StringUtils.join(columns, ","); db.execSQL(String.format( "INSERT INTO %s (%s) SELECT %s from temp_%s", TableName, cols, cols, TableName));
  • 刪除備份表(DROP table 'temp_" + TableName
  • setTransactionSuccessful

public static List<String> GetColumns(SQLiteDatabase db, String tableName) { 
    List<String> ar = null; 
    Cursor c = null; 
    try { 
     c = db.rawQuery("select * from " + tableName + " limit 1", null); 
     if (c != null) { 
      ar = new ArrayList<String>(Arrays.asList(c.getColumnNames())); 
     } 
    } catch (Exception e) { 
     Log.v(tableName, e.getMessage(), e); 
     e.printStackTrace(); 
    } finally { 
     if (c != null) 
      c.close(); 
    } 
    return ar; 
} 

public static String join(List<String> list, String delim) { 
    StringBuilder buf = new StringBuilder(); 
    int num = list.size(); 
    for (int i = 0; i < num; i++) { 
     if (i != 0) 
      buf.append(delim); 
     buf.append((String) list.get(i)); 
    } 
    return buf.toString(); 
} 
+0

我可以使用CREATE TEMPORARY TABLE IF NOT EXISTS而不是CREATE TABLE IF NOT EXISTS ? – 2010-08-06 15:33:42

+0

不,因爲當連接斷開時你會失去它。始終將表架構保持爲「CREATE TABLE IF NOT EXISTS」 – Pentium10 2010-08-06 15:38:15

+0

這與數據庫版本的結合如何? – 2010-08-06 16:03:56

1

這是我如何升級我的數據庫。

在我的應用程序的以前版本中,gameType列不存在。在新版本中,它的確如此。

void upgradeDatabase() throws IOException { 
    try { 
     String column = DatabaseConstants.GAME_TYPE_COLUMN_NAME; // gameType 
     String table = DatabaseConstants.RECORDS_TABLE; 
     String query = String.format("SELECT %s FROM %s LIMIT 1", column, table); 
     database.rawQuery(query, null); 
     return; 
    } 
    catch (Exception e) { 
     // Column doesn't exist. User had old version of app installed, so upgrade database. 
    } 

    // Save all old data 
    String query = "SELECT * FROM " + DatabaseConstants.USERS_TABLE; 
    Cursor c = database.rawQuery(query, null); 
    List<List<Object>> values1 = new ArrayList<List<Object>>(); 
    if (c.moveToFirst()) { 
     while (!c.isAfterLast()) { 
     List<Object> record = new ArrayList<Object>(); 
     record.add(c.getInt(0)); 
     record.add(c.getString(1)); 
     values1.add(record); 
     c.moveToNext(); 
     } 
    } 
    c.close(); 

    query = "SELECT * FROM " + DatabaseConstants.RECORDS_TABLE; 
    c = database.rawQuery(query, null); 
    List<List<Object>> values2 = new ArrayList<List<Object>>(); 
    if (c.moveToFirst()) { 
     while (!c.isAfterLast()) { 
     List<Object> record = new ArrayList<Object>(); 
     record.add(c.getInt(0)); 
     record.add(c.getInt(1)); 
     record.add(c.getInt(2)); 
     record.add(c.getInt(3)); 
     values2.add(record); 
     c.moveToNext(); 
     } 
    } 
    c.close(); 

    // Copy empty database with new schema 
    copyDatabase(); 

    // Restore all old data 
    for (List<Object> record : values1) { 
     ContentValues cv = new ContentValues(); 
     cv.put(DatabaseConstants.ID_COLUMN_NAME, (Integer) record.get(0)); 
     cv.put(DatabaseConstants.USERNAME_COLUMN_NAME, record.get(1).toString()); 
     database.insert(DatabaseConstants.USERS_TABLE, null, cv); 
    } 
    for (List<Object> record : values2) { 
     ContentValues cv = new ContentValues(); 
     cv.put(DatabaseConstants.USER_ID_COLUMN_NAME, (Integer) record.get(0)); 
     cv.put(DatabaseConstants.GAME_TYPE_COLUMN_NAME, GameType.CLASSIC.name()); 
     cv.put(DatabaseConstants.WINS_COLUMN_NAME, (Integer) record.get(1)); 
     cv.put(DatabaseConstants.LOSSES_COLUMN_NAME, (Integer) record.get(2)); 
     cv.put(DatabaseConstants.TIES_COLUMN_NAME, (Integer) record.get(3)); 
     database.insert(DatabaseConstants.RECORDS_TABLE, null, cv); 
    } 
    } 

下面是複製數據庫文件的代碼。數據庫最初是空的,我在我的應用程序之外創建它。 (我使用了一種叫做的Navicat SQLite的程序)。

public DatabaseHelper(Context context) { 
    super(context, DatabaseConstants.DATABASE_NAME, null, 1); 
    this.context = context; 
    databasePath = context.getDatabasePath(DatabaseConstants.DATABASE_NAME).getPath(); 
    } 

    void copyDatabase() throws IOException { 
    InputStream is = context.getAssets().open(DatabaseConstants.DATABASE_NAME); // data.db 
    OutputStream os = new FileOutputStream(databasePath); 

    byte[] buffer = new byte[1024]; 
    int length; 
    while ((length = is.read(buffer)) > 0) { 
     os.write(buffer, 0, length); 
    } 

    // Close the streams. 
    os.flush(); 
    os.close(); 
    is.close(); 
    } 
1

會不會像下面是爲絕大多數情況下更容易?只需添加新列的每個版本升級:

private static final String DATABASE_ALTER_TEAM_1 = "ALTER TABLE " 
    + TABLE_TEAM + " ADD COLUMN " + COLUMN_COACH + " string;"; 

private static final String DATABASE_ALTER_TEAM_2 = "ALTER TABLE " 
    + TABLE_TEAM + " ADD COLUMN " + COLUMN_STADIUM + " string;"; 

@Override 
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
    if (oldVersion < 2) { 
     db.execSQL(DATABASE_ALTER_TEAM_1); 
    } 
    if (oldVersion < 3) { 
     db.execSQL(DATABASE_ALTER_TEAM_2); 
    } 
} 

多一點這個,看看這個blog

相關問題