【问题标题】:Android SQLite Upgrade without losing dataAndroid SQLite 升级不丢失数据
【发布时间】:2012-10-14 00:17:04
【问题描述】:

我已经成功创建了一个 SQLite 数据库,它工作正常。但是,当调用 onUpgrade 方法时,我希望这样做不会丢失数据。我正在开发的应用程序是一个测验应用程序。简单地说,当调用 onCreate 方法时,我创建并预填充了一个包含问题、答案等的数据库。最后一列是他们是否将问题设置为收藏夹。我想做的是,当调用 onUpgrade 方法时,我想暂时保存一列,删除整个数据库,用我对旧问题所做的任何编辑重新创建它,然后添加任何新问题然后重新- 添加他们设置为收藏的问题。

所以我尝试的一个选项如下:

db.execSQL("ALTER TABLE quiz RENAME TO temp_quiz");
onCreate(db);
db.execSQL("INSERT INTO quiz (favouries) SELECT favourites FROM temp_quiz");
db.execSQL("DROP TABLE IF EXISTS temp_quiz");

但是这不起作用,因为 INSERT INTO 只是添加新行而不是替换现有行。我也尝试过 REPLACE INTO、INSERT OR REPLACE INTO 和

db.execSQL("INSERT INTO quiz (_id, favouries) SELECT _id, favourites FROM temp_quiz");

其中没有工作。

目前我确实通过更改表的名称、调用 onCreate(db) 方法然后设置一个游标来读取每一行并使用 db.update() 方法来设置它,如下所示:

int place = 1;
int TOTAL_NUMBER_OF_ROWS = 500;

while (place < TOTAL_NUMBER_OF_ROWS) {

String[] columns = new String[] { "_id", ..........., "FAVOURITES" };
// not included all the middle columns

Cursor c = db.query("temp_quiz", columns, "_id=" + place, null, null, null, null);

c.moveToFirst(); 

String s = c.getString(10);
// gets the value from the FAVOURITES column


ContentValues values = new ContentValues(); 
values.put(KEY_FLAG, s);

String where = KEY_ROWID + "=" + place;

db.update(DATABASE_TABLE, values, where, null);

place++;

c.close();

}

但是,虽然这很有效,但速度非常慢,而且随着我的问题数量增加,它只会变得更糟。有没有一种快速的方法来完成这一切?

谢谢!附:理想情况下,它应该只在该行存在时才更新该行。因此,如果在升级中我决定删除一个问题,它应该考虑到这一点,如果该行不包含任何其他数据,则不要添加新行。让它删除没有问题数据的行而不是阻止它们被添加可能更容易。

【问题讨论】:

    标签: android sqlite upgrade data-loss


    【解决方案1】:

    改为:

    db.execSQL("UPDATE new_quiz SET favourites = ( SELECT old_quiz.favourites 
    FROM old_quiz WHERE new_quiz._id = old_quiz._id) WHERE EXISTS 
    ( SELECT old_quiz.favourites FROM old_quiz WHERE new_quiz._id = old_quiz._id)");
    

    哪个有效:D

    【讨论】:

    • 我认为您的意思是“更新 new_quiz”,而不是 old_quiz =)
    • 对不起,我就是这个意思。谢谢:D
    • @AndroidPenguin,按照您在评论中的说明进行了修改。
    【解决方案2】:
    public class DataHelper extends SQLiteOpenHelper {
    
        private static final String dbName="dbName"; 
        private Context context;
        private  SQLiteDatabase db;
        private final static int version = 1;
    
        public  static final String SurveyTbl = "CREATE TABLE SurveyTbl (SurveyId TEXT PRIMARY KEY, Idref TEXT, SurveyDate TEXT)";
    
        public DataHelper(Context context) {
    
            super(context, dbName, null, version);
            this.db = getWritableDatabase();
            this.context = context;
            Log.i("", "********************DatabaseHelper(Context context)");
        }
    
    
    
        @Override
        public void onCreate(SQLiteDatabase db) {
    
            try {
    
            db.execSQL(SurveyTbl);
    
            } catch (Exception e) {
                Log.i("", "*******************onCreate");
            }
        }
    
    
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    
            try {
                db.execSQL("ALTER TABLE HandpumpSurveyTbl ADD COLUMN NalYozna TEXT");
    
    
    
            } catch (Exception e) {
                Log.i("", ""+e);
            }
    
    
             onCreate(db);
    
    
        }
    }
    

    【讨论】:

    • 在 onCreate 和 onUpdate 中捕获异常是个坏主意,因为这些方法的返回值用于确定是否回滚它们在其中执行的事务
    【解决方案3】:

    我没有看到您的测验表架构,但我认为它具有“问题”、“答案”、“收藏夹”等字段,以及用于识别每个问题的某种唯一主键,我将现在只需调用 rowId。

    // after renaming the old table and adding the new table
    db.execSQL("UPDATE new_quiz SET new_quiz.favorites = old_quiz.favorites where new_quiz.rowId = old_quiz.rowId");
    

    这将仅更新新测验​​表中与旧测验表匹配的行,并从旧测验表中设置收藏夹值。

    我假设您有某种唯一标识符来识别每个问题,因此您将使用它(问题编号或其他内容)而不是上面的 rowId。

    【讨论】:

    • 那没用:/由于这段时间,new_quiz.favourites 不断抛出错误。然后将其更改为仍然无法理解的收藏夹。最终用我的选择语句调整了你的答案并让它发挥作用:D
    • 啊我忘了 sqlite 不支持 JOIN on UPDATE =(
    【解决方案4】:

    对于不知道如何升级数据库架构的SQLite版本,例如,使用方法needUpgrade(int newVersion)!

    我的代码:

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
    
         if(newVersion>oldVersion){
    
             db.execSQL(scriptUpdate);
             db.needUpgrade(newVersion);
         }
    
    }
    

    【讨论】:

    • ononUpgrade() 总是在newVersion 的值高于oldVersion 时被调用,所以不需要那个 if 语句。
    【解决方案5】:
    ALTER TABLE mytable ADD COLUMN mycolumn TEXT
    

    在您的 onUpgrade 方法中,它看起来像这样:

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        String upgradeQuery = "ALTER TABLE mytable ADD COLUMN mycolumn TEXT";
        if (newVersion>oldVersion)
             db.execSQL(upgradeQuery);
    }
    

    【讨论】:

      【解决方案6】:

      例如,如何使用临时表删除表并创建新表而不丢失数据:

      db.execSQL("CREATE TEMPORARY TABLE temp_table (_id INTEGER PRIMARY KEY AUTOINCREMENT, col_1 TEXT, col_2 TEXT);");
      db.execSQL("INSERT INTO temp_table SELECT _id, col_1, col_2 FROM old_table");
      
      db.execSQL("CREATE TABLE new_table (_id INTEGER PRIMARY KEY AUTOINCREMENT, col_1 TEXT, col_2 TEXT, col_3 TEXT);");
      db.execSQL("INSERT INTO new_table SELECT _id, col_1, col_2, null FROM temp_table");
      
      db.execSQL("DROP TABLE old_table");
      db.execSQL("DROP TABLE temp_table");
      

      【讨论】:

        猜你喜欢
        • 2015-03-20
        • 1970-01-01
        • 1970-01-01
        • 2013-06-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-20
        • 1970-01-01
        相关资源
        最近更新 更多