2012-11-25 34 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 –

相關問題