2012-11-25 32 views
0

经过大量工作,我设法建立了我的第一个应用程序,但我坚持一个问题。对于我的应用程序,我正在使用sql数据库。假设我想将30条记录添加到某个表中。当我在android市场上推出一个新版本的SQL表格以便将来使用这个版本时,如何保留先前数据库的记录,这怎么可能?替换sql数据库,但保留旧的记录

它必须做一些事情:

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

编辑

我databasehelper代码:

public class DataBaseHelper extends SQLiteOpenHelper { 


    private static String DB_PATH = "/data/data/com.test.com/databases/"; 
    private static String DB_NAME = "quizDb"; 
    private SQLiteDatabase myDataBase; 
    private final Context myContext; 
    private Cursor c; 
    static int numberOfLevels = 10; 
    private final static int DB_VERSION = 2; // = until level 10 


    /** 
    * Constructor Takes and keeps a reference of the passed context in order to 
    * access to the application assets and resources. 
    * 
    * @param context 
    */ 
    public DataBaseHelper(Context context) { 
     super(context, DB_NAME, null, DB_VERSION); 
     this.myContext = context; 

    } 

    /** 
    * Creates a empty database on the system and rewrites it with your own 
    * database. 
    * */ 
    public void createDataBase() throws IOException { 

     boolean dbExist = checkDataBase(); 
     if (!dbExist) { 
      // By calling this method and empty database will be created into 
      // the default system path 
      // of your application so we are gonna be able to overwrite that 
      // database with our database. 
      this.getReadableDatabase(); 

      try { 
       copyDataBase(); 
      } catch (IOException e) { 
       throw new Error("Error copying database"); 
      } 
     } 
    } 

    /** 
    * Check if the database already exist to avoid re-copying the file each 
    * time you open the application. 
    * 
    * @return true if it exists, false if it doesn't 
    */ 
    private boolean checkDataBase() { 
     File dbFile = new File(DB_PATH + DB_NAME); 
     return dbFile.exists(); 
    } 

    /** 
    * Copies your database from your local assets-folder to the just created 
    * empty database in the system folder, from where it can be accessed and 
    * handled. This is done by transfering bytestream. 
    * */ 
    private void copyDataBase() throws IOException { 

     // Open your local db as the input stream 
     InputStream myInput = myContext.getAssets().open(DB_NAME); 

     // Path to the just created empty db 
     String outFileName = DB_PATH + DB_NAME; 

     // Open the empty db as the output stream 
     OutputStream myOutput = new FileOutputStream(outFileName); 

     // transfer bytes from the inputfile to the outputfile 
     byte[] buffer = new byte[1024]; 
     int length; 
     while ((length = myInput.read(buffer)) > 0) { 
      myOutput.write(buffer, 0, length); 
     } 

     // Close the streams 
     myOutput.flush(); 
     myOutput.close(); 
     myInput.close(); 

    } 

    public void openDataBase() throws SQLException { 
     // Open the database 
     String myPath = DB_PATH + DB_NAME; 

     myDataBase = SQLiteDatabase.openDatabase(myPath, null, 
       SQLiteDatabase.OPEN_READONLY); 
    } 

    @Override 
    public synchronized void close() { 
     if (c != null) 
      c.close(); 
     if (myDataBase != null) 
      myDataBase.close(); 

     super.close(); 
    } 

    @Override 
    public void onCreate(SQLiteDatabase db) { 

    } 

    public File getDatabasePath(String name) { 

     File file = myContext.getDatabasePath(name); 

     return file; 
    } 

    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     db.execSQL("ATTACH DATABASE ? as AttachedDB", 
       new String[] { getDatabasePath("quizDbNew").getPath() }); 
     db.execSQL("INSERT OR IGNORE INTO questions (_id, file, answer, level) SELECT _id, file, answer, level FROM AttachedDB.questions"); 
     db.execSQL("DETACH AttachedDB"); 

    } 

回答

3

使用onUpgrade()"DROP TABLE"的概念是为原始数据库管理得到,然而更有用的技术需要更多的SQL精明。通过使用"ALTER TABLE"添加新列或以其他方式将旧数据折叠到新的模式中来更新数据库的更智能的方法。


加成
低于你说的意见(或多或少):

我想将内容从我的数据库V1的备份文件复制到我目前的Db的V2

所以我们来设置一对假设表格:

  • 数据库版本一(DBv1):

    CREATE TABLE Foo(_id INTEGER PRIMARY KEY, bar TEXT, bar2 TEXT, bar3 TEXT); 
    
  • 数据库版本二(DBv2):

    CREATE TABLE Foo(_id INTEGER PRIMARY KEY, bar2 TEXT, bar4 INTEGER); 
    

首先,让我们看看从DBv1到DBv2定期升级。 SQLite仅支持ADD COLUMNRENAME TO,而不是REMOVE COLUMN或其他任何其他。因此,我们必须重新创建整个表:

@Override // DBv1 => DBv2 
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
    db.execSQL("ALTER TABLE Foo RENAME TO OldFoo"); 
    db.execSQL("CREATE TABLE Foo(_id INTEGER PRIMARY KEY, bar2 TEXT, bar4 INTEGER)"); 
    db.execSQL("INSERT INTO Foo (_id, bar) SELECT _id, bar2 FROM OldFoo"); 
    db.execSQL("DROP TABLE OldFoo"); 
} 

这又创造了一个表DBv2的模式,并保持所有从DBv1有效,现有的数据插入适当的列到DBv2。 (然后通过删除旧表来删除旧数据。)

您明智地选择了在单独的文件中随着时间的推移备份数据库,但是现在您希望将旧数据带入新的表模式。要开始确保备份SQLite文件与当前SQLite文件(data/data/<reverse.package.name>/databases/)位于同一目录中。它显然需要一个独特的名字,我们称之为DBBackup。现在,让我们重视DBBackup到当前的数据库,然后执行类似的动作从上面:

// DBBackupv1 => DBv2 
public void restore(SQLiteDatabase db) { 
    db.execSQL("ATTACH DATABASE ? as AttachedDB", new String[] {getDatabasePath("DBBackup").getPath()}); 
    db.execSQL("INSERT OR IGNORE INTO Foo (_id, bar2) SELECT _id, bar2 FROM AttachedDB.Foo"); 
    db.execSQL("DETACH AttachedDB"); 
} 

我以前INSERT OR IGNORE恢复被删除的所有行,但离开了当前存在的行不变。您可以使用INSERT OR REPLACE恢复到备份版本。还有更多选项可以满足您的需求。

+1

+1有一个很好的答案,但主要是为了在技术讨论中获得“finagle”。 – Simon

+0

我有一位老板使用[kerfuffle](https://www.google.com/search?q=define+kerfuffle)和[cattywampus](https://www.google.com/search?q=define + cattywampus)很多,事情经常被打破。 – Sam

+0

感谢您的回答!我想除此之外没有别的办法吗?由于我添加了db文件,只需将Db v1的两个表的内容复制到Db v2 –

相关问题