Question

In the tutorials I am following and a lot of more places I see this, onUpgrade -> drop table if exists, then recreate table.

What is the purpose of this?

private static class DbHelper extends SQLiteOpenHelper{

    public DbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" +
                KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
                KEY_NAME + " TEXT NOT NULL, " +
                KEY_HOTNESS + " TEXT NOT NULL);"
        );  
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
        onCreate(db);
    }       
}
Was it helpful?

Solution

I agree when you upgrade you should be adding columns or adding tables to your database. Most of the onupgrade samples actually suck because why am I deleting all this data then recreating the table? I found this blog entry I call it the Adams Incremental Update Method. It also handles situations where users may have not upgraded your app with each release.

Here is a good blog on sqlite onupgrade that doesn't do drop table.

OTHER TIPS

Well, the most common method in android applications is to "relog" the user when a database upgrade is in order. And considering any local database should only be mirroring what is on the serverside application, it is much easier to just drop the database, recreate it and repopulate from the server than it is to carefully plan migrations from one version to the other.

It certainly isn't the best approach, but it is easier.

To make an example of how it would be implementing a migration (a change from an older version of a database to a newer one)

Lets say in your DbHelper class you define that your database is version 1, in a later version of your application (version 2), you need a few more columns in one of your tables.

So you would need to upgrade your table and add the columns via ALTER TABLE {tableName} ADD COLUMN COLNew {type};

Check this link for that -> Insert new column into table in sqlite ?

so your onUpgrade() method would have to reflect that change by adding:

 @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    switch(oldVersion){
        case 1:
            db.execSQL("ALTER TABLE " + DATABASE_TABLE + " ADD COLUMN " + NEW_COLUMN_NAME + TYPE);
    }
}  

Depends on the kind of approach you want to create and how important your data, what complexity of table it is. Example: If your app has been upgraded quite a lot of times and table structure have change enough times, then its better to drop table and re-create it, rather than writing code for changing structure for every version of db, in this approach you will have to make sure that you can backup any data that you have on server side, so that things remain ok.

From my exp: recreating is better if you can judge that there might further be changes in future, else it gets quite complicated

It's a clean start. Method onCreate has the currently valid database structure. Users that install the app will execute this method. For the users that are upgrading, method onUpgrade will be executed, and DROP TABLE IF EXIST is a clean start - just in case the structure of the old and the new table is different - drop it and then recreate it in onCreate method. Hope this helps! :)

if you want to maintain the table data, you can dump it into CSV files then INSERT it back after the tables are created. (no need for dumping the data into a server) here is a sample code for dumping data. you can set the file name to be the table name. the cursor is created from a getAll statement

public boolean createCsvSaveToFile(Cursor cursor, String fileName) throws IOException {
    String csv = "";
    int colunmCount = cursor.getColumnCount();
    /* check if extarnal drive is readerble */
    if (!isExternalStorageWritable()) {
        fileError = "can not save to external storage";
        fileinfo = "Please mount your SD card";
        return false;
    } else {
        /* create the CSV */
        for (int i = 0; i < colunmCount; i++) {
            csv += QUOTES + cursor.getColumnName(i).toString() + QUOTES + INNER_DELIMITER;
        }
        csv = csv.replaceAll(",$", "");
        csv += LINE_END;
        if (cursor.moveToFirst()) {
            do {
                for (int i = 0; i < colunmCount; i++) {//GET COLUNM values
                    csv += QUOTES + cursor.getString(i) + QUOTES + INNER_DELIMITER;
                }
                csv = csv.replaceAll(",$", "");
                csv += LINE_END;
            } while (cursor.moveToNext());
        }
        /* save file */
        File file = getDataDir(fileName);
        FileOutputStream out = new FileOutputStream(file);
        out.write(csv.getBytes());
        out.flush();
        out.close();
        return true;
    }
}

here is a sample code for inserting the data. assuming the CSV file name is the same as the table name

private void readFromFile(SQLiteDatabase database, File file) {
    boolean hasColunms = false;
    String tableName = file.getName().replaceAll(".csv$", "");
    String sql;
    String colunmNames = "";
    String colunmValues;
    try {
        BufferedReader br = new BufferedReader(new FileReader(file));
        String line;
        while ((line = br.readLine()) != null) {
            if (!hasColunms ) {
                /* get column names */
                line = line.replaceAll("\"", "");
                colunmNames = line;
                hasColunms = true;
            } else {
                line = line.replaceAll("\"", "'");
                colunmValues = line;
                sql = "INSERT INTO " + tableName + " (" + colunmNames + ") VALUES (" + colunmValues + ")";
                database.execSQL(sql);
            }
        }
        br.close();
    } catch (IOException e) {
        database.close();
        /* You may need to add proper error handling here
    }

to loop through many csv files one can use the following code

public boolean csvTodatabase(SQLiteDatabase database) {
    FileStuff f = new FileStuff();
    File time;
    /* check if extarnal drive is readerble */
    if (!f.isExternalStorageReadable()) {
        f.fileError = "can not read external storage";
        f.fileinfo = "Please remount your SD card";
        return false;
    } else {
        /* get all files from extarnal drive data */
        ArrayList<File> files = new ArrayList<File>();
        File directory = new File(FileStuff.DATA_DIRECTORY);
        if (!directory.exists()) {
            return false;
        }
        File[] fList = directory.listFiles();
        for (File file : fList) {
            if (file.isFile()) {
                files.add(file);
            }
        }  
        for (File csvfile : files) {
            readFromFile(database, csvfile);
        }
        return true;
    }
}

NOTE: readFromFile(database, csvfile); is the previous function

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top