2010-08-06 95 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

相关问题