SQLite onUpgrade 删除和添加列
SQLite onUpgrade removing and adding column
在我的 Android 项目中,我使用了一段时间的 table。现在我想删除一列 'image_byte' 并添加一个新列 'image_path'。我不能在应用程序正在使用时重命名该列,它需要删除 image_byte 中的文本,这样它就不会再被使用了。
我实现了 SQLiteOpenHelper,下面的代码在 onUpgrade 中:
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
//check if upgrade is really needed
if(newVersion > oldVersion) {
tableSQL = "CREATE TABLE IF NOT EXISTS table1 ( id INTEGER PRIMARY KEY, name TEXT, image_path TEXT)";
db.execSQL(tableSQL);
//get all the current tableName table columns
List<String> columns = getColumns(db, "table1");
//rename the old table
db.execSQL("ALTER TABLE table1 RENAME TO temp_table1;");
//create the new tableName table
db.execSQL(tableSQL);
//merge the old and new columns, keep all the old ones
columns.retainAll(getColumns(db, "table1"));
String cols = joinColumnNames(columns, ",");
//insert the old data in the new table
db.execSQL(String.format("INSERT INTO %s (%s) SELECT %s FROM temp_%s", "table1", cols, cols, "table1"));
//delete the old temp table
db.execSQL("DROP table 'temp_table1'");
}
}
和 getColumns 函数:
private 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< >(Arrays.asList(c.getColumnNames()));
}
} catch (Exception e){
} finally {
if (c != null){
c.close();
}
}
return ar;
}
但是在调试应用程序时,它说 'image_byte' 列不存在并且无法将内容从 temp_table1 复制到 table1。这是正确的,因为它现在是 'image_path' 并且不应复制 image_byte。但为什么 getColumns 返回旧列?因为我用Log.d的时候,显示的是'id'、'name'、'image_byte'。因此 retainAll 函数不会删除 'image_byte'。我似乎无法弄清楚为什么它仍然 returns image_byte。这可能是愚蠢和简单的,但我只是看不到它。
我认为问题很可能是由于缓存引起的,因为 columns.retainAll(getColumns(db, "table1"));
似乎从原始 table1.
中检索列
这是我进行的一些测试的结果:-
10-15 13:37:19.319 26740-26740/? D/DBINFO: onUpgrade Started.
10-15 13:37:19.320 26740-26740/? D/DBINFO: Databse info in onUpgrade after table rename to temp_table1
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: DatabaseList Row 1 Name=main File=/data/data/mjt.sqlitedbexamples/databases/imagestore
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: Database Version = 1
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: Table Name = android_metadata Created Using = CREATE TABLE android_metadata (locale TEXT)
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: Table = android_metadata ColumnName = locale ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: Table Name = temp_table1 Created Using = CREATE TABLE "temp_table1"(id INTEGER PRIMARY KEY,name TEXT,image_byte TEXT)
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: Table = temp_table1 ColumnName = id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: Table = temp_table1 ColumnName = name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: Table = temp_table1 ColumnName = image_byte ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.321 26740-26740/? D/DBINFO: Databse info in onUpgrade after creation of new table1.
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: DatabaseList Row 1 Name=main File=/data/data/mjt.sqlitedbexamples/databases/imagestore
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Database Version = 1
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table Name = android_metadata Created Using = CREATE TABLE android_metadata (locale TEXT)
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table = android_metadata ColumnName = locale ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table Name = temp_table1 Created Using = CREATE TABLE "temp_table1"(id INTEGER PRIMARY KEY,name TEXT,image_byte TEXT)
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table = temp_table1 ColumnName = id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table = temp_table1 ColumnName = name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table = temp_table1 ColumnName = image_byte ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table Name = table1 Created Using = CREATE TABLE table1(id INTEGER PRIMARY KEY, name TEXT,image_path TEXT)
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table = table1 ColumnName = id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table = table1 ColumnName = name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table = table1 ColumnName = image_path ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.321 26740-26740/? D/ORIG COLUMNS: Orignal Column Info - Column=id Column=name Column=image_byte
10-15 13:37:19.321 26740-26740/? D/NEWTAB COLUMNS: Columns from new table1 - Column=id Column=name Column=image_byte
10-15 13:37:19.321 26740-26740/? D/RETAIN COLUMNS: Columns After Retain - Column=id Column=name Column=image_byte
10-15 13:37:19.321 26740-26740/? D/JOINED COLUMNS: id,name,image_byte
10-15 13:37:19.321 26740-26740/? E/SQLiteLog: (1) table table1 has no column named image_byte
10-15 13:37:19.329 26740-26740/? D/AndroidRuntime: Shutting down VM
最后几行 D/ORIG 列,D/NEWTAB 列,D/RETAIN 列。 D/RETAIN COLUMNS 表示已提取 image_byte。
也许引入一个中间 table 名称,然后最终将其重命名为原始 table 名称可能会解决该问题。
请注意 SQLITE_CSU 输出是由提到的实用程序生成的 。
这是用于 testing/producing 以上的 onUpgrade 代码:-
@Override
public void onUpgrade(SQLiteDatabase db, int oldversion, int newversion) {
String tableSQL = "CREATE TABLE IF NOT EXISTS " + TBNAME + "(" +
"id INTEGER PRIMARY KEY, " +
"name TEXT," +
"image_path TEXT" +
")";
if (newversion > oldversion) {
Log.d("DBINFO","onUpgrade Started.");
db.execSQL(tableSQL);
//get all the current tableName table columns
List<String> columns = getColumns(db, "table1");
//rename the old table
db.execSQL("ALTER TABLE table1 RENAME TO temp_table1;");
Log.d("DBINFO","Databse info in onUpgrade after table rename to temp_table1");
CommonSQLiteUtilities.logDatabaseInfo(db);
//create the new tableName table
db.execSQL(tableSQL);
Log.d("DBINFO","Databse info in onUpgrade after creation of new table1.");
CommonSQLiteUtilities.logDatabaseInfo(db);
//merge the old and new columns, keep all the old ones
String loginfo = "Orignal Column Info - ";
for (String s:columns) {
loginfo = loginfo + "Column=" + s + " ";
}
Log.d("ORIG COLUMNS",loginfo);
loginfo = "Columns from new table1 - ";
for (String s: getColumns(db, "table1")) {
loginfo = loginfo + "Column=" + s + " ";
}
Log.d("NEWTAB COLUMNS",loginfo);
columns.retainAll(getColumns(db, "table1"));
loginfo = "Columns After Retain - ";
for (String s: columns) {
loginfo = loginfo + "Column=" + s + " ";
}
Log.d("RETAIN COLUMNS",loginfo);
String cols = joinColumnNames(columns, ",");
Log.d("JOINED COLUMNS",cols);
//insert the old data in the new table
db.execSQL(String.format("INSERT INTO %s (%s) SELECT %s FROM temp_%s", "table1", cols, cols, "table1"));
//delete the old temp table
db.execSQL("DROP table 'temp_table1'");
Log.d("DBINFO","Databse info in onUpgrade after DELETING temp_table1.");
}
工作示例:-
在此示例中,数据从原始 table 提取到 Cursor 中,新的 table 使用不同的名称创建,这个新的 table 加载了数据然后旧的 table 被删除,最后新的 table 被重命名。
这可能会稍微复杂一些,因为它维护了 id,不过它只有 1 行 :-
cv.put("id",Long.toString(olddata.getLong(olddata.getColumnIndex("id"))));
注意!带有 //<<<<<
的 commenetd 行纯粹用于记录 activity。尽管如果旧数据光标为 read/traversed 则需要 olddata.moveToPosition(-1); //<<<<<
(即 return 第一行之前的位置)。
@Override
public void onUpgrade(SQLiteDatabase db, int oldversion, int newversion) {
String temptableSQL = "CREATE TABLE IF NOT EXISTS temp_" + TBNAME + "(" +
"id INTEGER PRIMARY KEY, " +
"name TEXT," +
"image_path TEXT" +
")";
if (newversion > oldversion) {
Log.d("DBINFO","onUpgrade Started.");
db.execSQL(temptableSQL);
Cursor olddata = db.query(TBNAME,null,null,null,null,null,null);
CommonSQLiteUtilities.logCursorData(olddata); //<<<<
olddata.moveToPosition(-1); //<<<<<
//db.execSQL(tableSQL);
Log.d("DBINFO","Databse info in onUpgrade after creation of new table1.");
CommonSQLiteUtilities.logDatabaseInfo(db); //<<<<<
Log.d("DBCOPYDATA",
"Copying data from OLD Data. # rows = " +
Integer.toString(olddata.getCount())
); //<<<<<
while (olddata.moveToNext()) {
ContentValues cv = new ContentValues();
Log.d("DBCOPYDATA","ROW " + Integer.toString(olddata.getPosition()) +
"\n\tID=" + Long.toString(olddata.getLong(olddata.getColumnIndex("id"))) +
"\n\tNAME=" + olddata.getString(olddata.getColumnIndex("name")) +
"\n\tIMG =" + olddata.getString(olddata.getColumnIndex("image_byte"))
); //<<<<<
cv.put("id",Long.toString(olddata.getLong(olddata.getColumnIndex("id"))));
cv.put("name",olddata.getString(olddata.getColumnIndex("name")));
cv.put("image_path",olddata.getString(olddata.getColumnIndex("image_byte")));
Long id = db.insert("temp_" + TBNAME,null,cv);
Log.d("DBCOPYDATA","INSERTED ID=" + Long.toString(id)); //<<<<<
}
olddata.close();
db.execSQL("DROP TABLE IF EXISTS " + TBNAME);
db.execSQL("ALTER TABLE temp_" + TBNAME + " RENAME TO " + TBNAME);
Cursor csr = db.query(TBNAME,null,null,null,null,null,null); //<<<<<
CommonSQLiteUtilities.logDatabaseInfo(db); //<<<<<
CommonSQLiteUtilities.logCursorData(csr); //<<<<<
csr.close(); //<<<<<
}
}
成功测试的输出:-
10-15 17:54:41.618 16960-16960/? D/DBINFO: onUpgrade Started.
10-15 17:54:41.619 16960-16960/? D/SQLITE_CSU: logCursorData Cursor has 3 rows with 3 columns.
10-15 17:54:41.619 16960-16960/? D/SQLITE_CSU: Information for row 1 offset=0
For Column id Type is INTEGER value as String is 1 value as long is 1 value as double is 1.0
For Column name Type is STRING value as String is Test001 value as long is 0 value as double is 0.0
For Column image_byte Type is STRING value as String is mypath/mypath/images/image001 value as long is 0 value as double is 0.0
10-15 17:54:41.619 16960-16960/? D/SQLITE_CSU: Information for row 2 offset=1
For Column id Type is INTEGER value as String is 2 value as long is 2 value as double is 2.0
For Column name Type is STRING value as String is Test001 value as long is 0 value as double is 0.0
For Column image_byte Type is STRING value as String is mypath/mypath/images/image002 value as long is 0 value as double is 0.0
10-15 17:54:41.619 16960-16960/? D/SQLITE_CSU: Information for row 3 offset=2
For Column id Type is INTEGER value as String is 3 value as long is 3 value as double is 3.0
For Column name Type is STRING value as String is Test001 value as long is 0 value as double is 0.0
For Column image_byte Type is STRING value as String is mypath/mypath/images/image003 value as long is 0 value as double is 0.0
10-15 17:54:41.619 16960-16960/? D/DBINFO: Databse info in onUpgrade after creation of new table1.
10-15 17:54:41.619 16960-16960/? D/SQLITE_CSU: DatabaseList Row 1 Name=main File=/data/data/mjt.sqlitedbexamples/databases/imagestore
10-15 17:54:41.619 16960-16960/? D/SQLITE_CSU: Database Version = 1
10-15 17:54:41.619 16960-16960/? D/SQLITE_CSU: Table Name = android_metadata Created Using = CREATE TABLE android_metadata (locale TEXT)
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table = android_metadata ColumnName = locale ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table Name = table1 Created Using = CREATE TABLE table1(id INTEGER PRIMARY KEY,name TEXT,image_byte TEXT)
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table = table1 ColumnName = id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table = table1 ColumnName = name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table = table1 ColumnName = image_byte ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table Name = temp_table1 Created Using = CREATE TABLE temp_table1(id INTEGER PRIMARY KEY, name TEXT,image_path TEXT)
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table = temp_table1 ColumnName = id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table = temp_table1 ColumnName = name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table = temp_table1 ColumnName = image_path ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.620 16960-16960/? D/DBCOPYDATA: Copying data from OLD Data. # rows = 3
10-15 17:54:41.620 16960-16960/? D/DBCOPYDATA: ROW 0
ID=1
NAME=Test001
IMG =mypath/mypath/images/image001
10-15 17:54:41.620 16960-16960/? D/DBCOPYDATA: INSERTED ID=1
10-15 17:54:41.620 16960-16960/? D/DBCOPYDATA: ROW 1
ID=2
NAME=Test001
IMG =mypath/mypath/images/image002
10-15 17:54:41.620 16960-16960/? D/DBCOPYDATA: INSERTED ID=2
10-15 17:54:41.620 16960-16960/? D/DBCOPYDATA: ROW 2
ID=3
NAME=Test001
IMG =mypath/mypath/images/image003
10-15 17:54:41.620 16960-16960/? D/DBCOPYDATA: INSERTED ID=3
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: DatabaseList Row 1 Name=main File=/data/data/mjt.sqlitedbexamples/databases/imagestore
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Database Version = 1
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Table Name = android_metadata Created Using = CREATE TABLE android_metadata (locale TEXT)
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Table = android_metadata ColumnName = locale ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Table Name = table1 Created Using = CREATE TABLE "table1"(id INTEGER PRIMARY KEY, name TEXT,image_path TEXT)
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Table = table1 ColumnName = id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Table = table1 ColumnName = name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Table = table1 ColumnName = image_path ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: logCursorData Cursor has 3 rows with 3 columns.
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Information for row 1 offset=0
For Column id Type is INTEGER value as String is 1 value as long is 1 value as double is 1.0
For Column name Type is STRING value as String is Test001 value as long is 0 value as double is 0.0
For Column image_byte Type is STRING value as String is mypath/mypath/images/image001 value as long is 0 value as double is 0.0
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Information for row 2 offset=1
For Column id Type is INTEGER value as String is 2 value as long is 2 value as double is 2.0
For Column name Type is STRING value as String is Test001 value as long is 0 value as double is 0.0
For Column image_byte Type is STRING value as String is mypath/mypath/images/image002 value as long is 0 value as double is 0.0
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Information for row 3 offset=2
For Column id Type is INTEGER value as String is 3 value as long is 3 value as double is 3.0
For Column name Type is STRING value as String is Test001 value as long is 0 value as double is 0.0
For Column image_byte Type is STRING value as String is mypath/mypath/images/image003 value as long is 0 value as double is 0.0
在我的 Android 项目中,我使用了一段时间的 table。现在我想删除一列 'image_byte' 并添加一个新列 'image_path'。我不能在应用程序正在使用时重命名该列,它需要删除 image_byte 中的文本,这样它就不会再被使用了。
我实现了 SQLiteOpenHelper,下面的代码在 onUpgrade 中:
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
//check if upgrade is really needed
if(newVersion > oldVersion) {
tableSQL = "CREATE TABLE IF NOT EXISTS table1 ( id INTEGER PRIMARY KEY, name TEXT, image_path TEXT)";
db.execSQL(tableSQL);
//get all the current tableName table columns
List<String> columns = getColumns(db, "table1");
//rename the old table
db.execSQL("ALTER TABLE table1 RENAME TO temp_table1;");
//create the new tableName table
db.execSQL(tableSQL);
//merge the old and new columns, keep all the old ones
columns.retainAll(getColumns(db, "table1"));
String cols = joinColumnNames(columns, ",");
//insert the old data in the new table
db.execSQL(String.format("INSERT INTO %s (%s) SELECT %s FROM temp_%s", "table1", cols, cols, "table1"));
//delete the old temp table
db.execSQL("DROP table 'temp_table1'");
}
}
和 getColumns 函数:
private 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< >(Arrays.asList(c.getColumnNames()));
}
} catch (Exception e){
} finally {
if (c != null){
c.close();
}
}
return ar;
}
但是在调试应用程序时,它说 'image_byte' 列不存在并且无法将内容从 temp_table1 复制到 table1。这是正确的,因为它现在是 'image_path' 并且不应复制 image_byte。但为什么 getColumns 返回旧列?因为我用Log.d的时候,显示的是'id'、'name'、'image_byte'。因此 retainAll 函数不会删除 'image_byte'。我似乎无法弄清楚为什么它仍然 returns image_byte。这可能是愚蠢和简单的,但我只是看不到它。
我认为问题很可能是由于缓存引起的,因为 columns.retainAll(getColumns(db, "table1"));
似乎从原始 table1.
这是我进行的一些测试的结果:-
10-15 13:37:19.319 26740-26740/? D/DBINFO: onUpgrade Started.
10-15 13:37:19.320 26740-26740/? D/DBINFO: Databse info in onUpgrade after table rename to temp_table1
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: DatabaseList Row 1 Name=main File=/data/data/mjt.sqlitedbexamples/databases/imagestore
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: Database Version = 1
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: Table Name = android_metadata Created Using = CREATE TABLE android_metadata (locale TEXT)
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: Table = android_metadata ColumnName = locale ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: Table Name = temp_table1 Created Using = CREATE TABLE "temp_table1"(id INTEGER PRIMARY KEY,name TEXT,image_byte TEXT)
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: Table = temp_table1 ColumnName = id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: Table = temp_table1 ColumnName = name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.320 26740-26740/? D/SQLITE_CSU: Table = temp_table1 ColumnName = image_byte ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.321 26740-26740/? D/DBINFO: Databse info in onUpgrade after creation of new table1.
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: DatabaseList Row 1 Name=main File=/data/data/mjt.sqlitedbexamples/databases/imagestore
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Database Version = 1
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table Name = android_metadata Created Using = CREATE TABLE android_metadata (locale TEXT)
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table = android_metadata ColumnName = locale ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table Name = temp_table1 Created Using = CREATE TABLE "temp_table1"(id INTEGER PRIMARY KEY,name TEXT,image_byte TEXT)
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table = temp_table1 ColumnName = id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table = temp_table1 ColumnName = name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table = temp_table1 ColumnName = image_byte ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table Name = table1 Created Using = CREATE TABLE table1(id INTEGER PRIMARY KEY, name TEXT,image_path TEXT)
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table = table1 ColumnName = id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table = table1 ColumnName = name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.321 26740-26740/? D/SQLITE_CSU: Table = table1 ColumnName = image_path ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 13:37:19.321 26740-26740/? D/ORIG COLUMNS: Orignal Column Info - Column=id Column=name Column=image_byte
10-15 13:37:19.321 26740-26740/? D/NEWTAB COLUMNS: Columns from new table1 - Column=id Column=name Column=image_byte
10-15 13:37:19.321 26740-26740/? D/RETAIN COLUMNS: Columns After Retain - Column=id Column=name Column=image_byte
10-15 13:37:19.321 26740-26740/? D/JOINED COLUMNS: id,name,image_byte
10-15 13:37:19.321 26740-26740/? E/SQLiteLog: (1) table table1 has no column named image_byte
10-15 13:37:19.329 26740-26740/? D/AndroidRuntime: Shutting down VM
最后几行 D/ORIG 列,D/NEWTAB 列,D/RETAIN 列。 D/RETAIN COLUMNS 表示已提取 image_byte。
也许引入一个中间 table 名称,然后最终将其重命名为原始 table 名称可能会解决该问题。
请注意 SQLITE_CSU 输出是由提到的实用程序生成的
这是用于 testing/producing 以上的 onUpgrade 代码:-
@Override
public void onUpgrade(SQLiteDatabase db, int oldversion, int newversion) {
String tableSQL = "CREATE TABLE IF NOT EXISTS " + TBNAME + "(" +
"id INTEGER PRIMARY KEY, " +
"name TEXT," +
"image_path TEXT" +
")";
if (newversion > oldversion) {
Log.d("DBINFO","onUpgrade Started.");
db.execSQL(tableSQL);
//get all the current tableName table columns
List<String> columns = getColumns(db, "table1");
//rename the old table
db.execSQL("ALTER TABLE table1 RENAME TO temp_table1;");
Log.d("DBINFO","Databse info in onUpgrade after table rename to temp_table1");
CommonSQLiteUtilities.logDatabaseInfo(db);
//create the new tableName table
db.execSQL(tableSQL);
Log.d("DBINFO","Databse info in onUpgrade after creation of new table1.");
CommonSQLiteUtilities.logDatabaseInfo(db);
//merge the old and new columns, keep all the old ones
String loginfo = "Orignal Column Info - ";
for (String s:columns) {
loginfo = loginfo + "Column=" + s + " ";
}
Log.d("ORIG COLUMNS",loginfo);
loginfo = "Columns from new table1 - ";
for (String s: getColumns(db, "table1")) {
loginfo = loginfo + "Column=" + s + " ";
}
Log.d("NEWTAB COLUMNS",loginfo);
columns.retainAll(getColumns(db, "table1"));
loginfo = "Columns After Retain - ";
for (String s: columns) {
loginfo = loginfo + "Column=" + s + " ";
}
Log.d("RETAIN COLUMNS",loginfo);
String cols = joinColumnNames(columns, ",");
Log.d("JOINED COLUMNS",cols);
//insert the old data in the new table
db.execSQL(String.format("INSERT INTO %s (%s) SELECT %s FROM temp_%s", "table1", cols, cols, "table1"));
//delete the old temp table
db.execSQL("DROP table 'temp_table1'");
Log.d("DBINFO","Databse info in onUpgrade after DELETING temp_table1.");
}
工作示例:-
在此示例中,数据从原始 table 提取到 Cursor 中,新的 table 使用不同的名称创建,这个新的 table 加载了数据然后旧的 table 被删除,最后新的 table 被重命名。
这可能会稍微复杂一些,因为它维护了 id,不过它只有 1 行 :-
cv.put("id",Long.toString(olddata.getLong(olddata.getColumnIndex("id"))));
注意!带有 //<<<<<
的 commenetd 行纯粹用于记录 activity。尽管如果旧数据光标为 read/traversed 则需要 olddata.moveToPosition(-1); //<<<<<
(即 return 第一行之前的位置)。
@Override
public void onUpgrade(SQLiteDatabase db, int oldversion, int newversion) {
String temptableSQL = "CREATE TABLE IF NOT EXISTS temp_" + TBNAME + "(" +
"id INTEGER PRIMARY KEY, " +
"name TEXT," +
"image_path TEXT" +
")";
if (newversion > oldversion) {
Log.d("DBINFO","onUpgrade Started.");
db.execSQL(temptableSQL);
Cursor olddata = db.query(TBNAME,null,null,null,null,null,null);
CommonSQLiteUtilities.logCursorData(olddata); //<<<<
olddata.moveToPosition(-1); //<<<<<
//db.execSQL(tableSQL);
Log.d("DBINFO","Databse info in onUpgrade after creation of new table1.");
CommonSQLiteUtilities.logDatabaseInfo(db); //<<<<<
Log.d("DBCOPYDATA",
"Copying data from OLD Data. # rows = " +
Integer.toString(olddata.getCount())
); //<<<<<
while (olddata.moveToNext()) {
ContentValues cv = new ContentValues();
Log.d("DBCOPYDATA","ROW " + Integer.toString(olddata.getPosition()) +
"\n\tID=" + Long.toString(olddata.getLong(olddata.getColumnIndex("id"))) +
"\n\tNAME=" + olddata.getString(olddata.getColumnIndex("name")) +
"\n\tIMG =" + olddata.getString(olddata.getColumnIndex("image_byte"))
); //<<<<<
cv.put("id",Long.toString(olddata.getLong(olddata.getColumnIndex("id"))));
cv.put("name",olddata.getString(olddata.getColumnIndex("name")));
cv.put("image_path",olddata.getString(olddata.getColumnIndex("image_byte")));
Long id = db.insert("temp_" + TBNAME,null,cv);
Log.d("DBCOPYDATA","INSERTED ID=" + Long.toString(id)); //<<<<<
}
olddata.close();
db.execSQL("DROP TABLE IF EXISTS " + TBNAME);
db.execSQL("ALTER TABLE temp_" + TBNAME + " RENAME TO " + TBNAME);
Cursor csr = db.query(TBNAME,null,null,null,null,null,null); //<<<<<
CommonSQLiteUtilities.logDatabaseInfo(db); //<<<<<
CommonSQLiteUtilities.logCursorData(csr); //<<<<<
csr.close(); //<<<<<
}
}
成功测试的输出:-
10-15 17:54:41.618 16960-16960/? D/DBINFO: onUpgrade Started.
10-15 17:54:41.619 16960-16960/? D/SQLITE_CSU: logCursorData Cursor has 3 rows with 3 columns.
10-15 17:54:41.619 16960-16960/? D/SQLITE_CSU: Information for row 1 offset=0
For Column id Type is INTEGER value as String is 1 value as long is 1 value as double is 1.0
For Column name Type is STRING value as String is Test001 value as long is 0 value as double is 0.0
For Column image_byte Type is STRING value as String is mypath/mypath/images/image001 value as long is 0 value as double is 0.0
10-15 17:54:41.619 16960-16960/? D/SQLITE_CSU: Information for row 2 offset=1
For Column id Type is INTEGER value as String is 2 value as long is 2 value as double is 2.0
For Column name Type is STRING value as String is Test001 value as long is 0 value as double is 0.0
For Column image_byte Type is STRING value as String is mypath/mypath/images/image002 value as long is 0 value as double is 0.0
10-15 17:54:41.619 16960-16960/? D/SQLITE_CSU: Information for row 3 offset=2
For Column id Type is INTEGER value as String is 3 value as long is 3 value as double is 3.0
For Column name Type is STRING value as String is Test001 value as long is 0 value as double is 0.0
For Column image_byte Type is STRING value as String is mypath/mypath/images/image003 value as long is 0 value as double is 0.0
10-15 17:54:41.619 16960-16960/? D/DBINFO: Databse info in onUpgrade after creation of new table1.
10-15 17:54:41.619 16960-16960/? D/SQLITE_CSU: DatabaseList Row 1 Name=main File=/data/data/mjt.sqlitedbexamples/databases/imagestore
10-15 17:54:41.619 16960-16960/? D/SQLITE_CSU: Database Version = 1
10-15 17:54:41.619 16960-16960/? D/SQLITE_CSU: Table Name = android_metadata Created Using = CREATE TABLE android_metadata (locale TEXT)
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table = android_metadata ColumnName = locale ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table Name = table1 Created Using = CREATE TABLE table1(id INTEGER PRIMARY KEY,name TEXT,image_byte TEXT)
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table = table1 ColumnName = id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table = table1 ColumnName = name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table = table1 ColumnName = image_byte ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table Name = temp_table1 Created Using = CREATE TABLE temp_table1(id INTEGER PRIMARY KEY, name TEXT,image_path TEXT)
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table = temp_table1 ColumnName = id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table = temp_table1 ColumnName = name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.620 16960-16960/? D/SQLITE_CSU: Table = temp_table1 ColumnName = image_path ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.620 16960-16960/? D/DBCOPYDATA: Copying data from OLD Data. # rows = 3
10-15 17:54:41.620 16960-16960/? D/DBCOPYDATA: ROW 0
ID=1
NAME=Test001
IMG =mypath/mypath/images/image001
10-15 17:54:41.620 16960-16960/? D/DBCOPYDATA: INSERTED ID=1
10-15 17:54:41.620 16960-16960/? D/DBCOPYDATA: ROW 1
ID=2
NAME=Test001
IMG =mypath/mypath/images/image002
10-15 17:54:41.620 16960-16960/? D/DBCOPYDATA: INSERTED ID=2
10-15 17:54:41.620 16960-16960/? D/DBCOPYDATA: ROW 2
ID=3
NAME=Test001
IMG =mypath/mypath/images/image003
10-15 17:54:41.620 16960-16960/? D/DBCOPYDATA: INSERTED ID=3
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: DatabaseList Row 1 Name=main File=/data/data/mjt.sqlitedbexamples/databases/imagestore
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Database Version = 1
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Table Name = android_metadata Created Using = CREATE TABLE android_metadata (locale TEXT)
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Table = android_metadata ColumnName = locale ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Table Name = table1 Created Using = CREATE TABLE "table1"(id INTEGER PRIMARY KEY, name TEXT,image_path TEXT)
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Table = table1 ColumnName = id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Table = table1 ColumnName = name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Table = table1 ColumnName = image_path ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: logCursorData Cursor has 3 rows with 3 columns.
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Information for row 1 offset=0
For Column id Type is INTEGER value as String is 1 value as long is 1 value as double is 1.0
For Column name Type is STRING value as String is Test001 value as long is 0 value as double is 0.0
For Column image_byte Type is STRING value as String is mypath/mypath/images/image001 value as long is 0 value as double is 0.0
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Information for row 2 offset=1
For Column id Type is INTEGER value as String is 2 value as long is 2 value as double is 2.0
For Column name Type is STRING value as String is Test001 value as long is 0 value as double is 0.0
For Column image_byte Type is STRING value as String is mypath/mypath/images/image002 value as long is 0 value as double is 0.0
10-15 17:54:41.621 16960-16960/? D/SQLITE_CSU: Information for row 3 offset=2
For Column id Type is INTEGER value as String is 3 value as long is 3 value as double is 3.0
For Column name Type is STRING value as String is Test001 value as long is 0 value as double is 0.0
For Column image_byte Type is STRING value as String is mypath/mypath/images/image003 value as long is 0 value as double is 0.0