仅使用 SQL 命令可以进行这种迁移吗?
是的,至少可以达到最终的结果。
但是,start_time 的格式很重要。
此外,可能不需要迁移,因为 start_time 的格式很可能动态转换结果并且不会两次存储相同的信息。
假设 start_time 的格式为 YYYY-MM-DD hh:mm 例如2021-10-01 10:25 那么由于格式是 SQLite 可识别的格式,您可以在查询表时使用 strftime('%s',start_time) AS start_time_int 获取长版本,并且将有一个 start_time_int 列,它是一个整数(长)。
这是一个演示应用程序,它显示了基于上述格式的 start_time 的两种技术。
数据库有两个表 table1 和 table2,它们最初具有相同的架构 _id 列和 start_time 栏目。
当数据库版本从 1 增加到 2 时,通过 ALTER TABLE table1 ADD COLUMN start_time_int INTEGER 在 onUpgrade 方法中添加一个额外的列 start_time_int,这之后是一个 UPDATE table1 SET start_time_int = strftime('%s',start_time) WHERE start_time_int IS NULL; 设置 start_time_int 值(因为在 start_time_int 列定义中没有指定 DEFAULT,所以设置为 null)。
- 请注意,为了适应新安装,
onCreate 版本也已更改。由于此演示旨在测试版本之间的切换,onCreate 方法具有应用相应表创建的逻辑。
但是,table2 保持不变。此表用于说明无需更改表,因为 Long 值很容易提取。
数据库助手(扩展 SQLiteOpenHelper 的类)DBHelper :-
class DBHelper extends SQLiteOpenHelper {
public static final String DBNAME = "thedatabase.db";
public static final int DBVERSION = 1; /*<<<<<<<< */
public static final String TABLE1_NAME = "table1";
public static final String TABLE2_NAME = "table2";
public static final String ID_COLUMN = BaseColumns._ID;
public static final String START_TIME_COLUMN = "start_time";
public static final String START_TIME_INT_COLUMN = "start_time_int";
SQLiteDatabase db;
private static volatile DBHelper instance;
private DBHelper(Context context) {
super(context,DBNAME,null,DBVERSION);
db = this.getWritableDatabase();
}
public static DBHelper getInstance(Context context) {
if (instance == null) {
instance = new DBHelper(context);
}
return instance;
}
@Override
public void onCreate(SQLiteDatabase db) {
if (DBVERSION == 1) {
db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE1_NAME + " (" +
ID_COLUMN + " INTEGER PRIMARY KEY" +
", " + START_TIME_COLUMN + " TEXT" +
")");
} else {
db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE1_NAME + " (" +
ID_COLUMN + " INTEGER PRIMARY KEY" +
", " + START_TIME_COLUMN + " TEXT " +
", " + START_TIME_INT_COLUMN + " INTEGER " +
")");
}
db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE2_NAME + " (" +
ID_COLUMN + " INTEGER PRIMARY KEY" +
", " + START_TIME_COLUMN + " TEXT" +
")");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 2) {
Log.d("ONUPGRADE", "On Upgrade called. Oldversion is " + oldVersion + " New version is " + newVersion);
db.execSQL("ALTER TABLE " + TABLE1_NAME + " ADD COLUMN " + START_TIME_INT_COLUMN + " INTEGER;");
db.execSQL("UPDATE " + TABLE1_NAME + " SET " + START_TIME_INT_COLUMN + " = strftime('%s'," + START_TIME_COLUMN + ") WHERE " + START_TIME_INT_COLUMN + " IS NULL;");
}
}
public long insert(String tableName, String start_time) {
ContentValues cv = new ContentValues();
cv.put(START_TIME_COLUMN,start_time);
return db.insert(tableName,null,cv);
}
@SuppressLint("Range")
public void logTable2() {
Cursor csr = db.query(TABLE2_NAME,
new String[]{
ID_COLUMN,
START_TIME_COLUMN,
"strftime('%s'," + START_TIME_COLUMN + ") AS " + START_TIME_INT_COLUMN
},
null,null,null,null,null
);
while(csr.moveToNext()) {
Log.d(
"TABLE2INFO",
"StartTime = " + csr.getString(csr.getColumnIndex(START_TIME_COLUMN)) +
" AS INTEGER(long) " + csr.getLong(csr.getColumnIndex(START_TIME_INT_COLUMN))
);
}
}
@SuppressLint("Range")
public void logTable1V1() {
Cursor csr = db.query(TABLE2_NAME,
null, /* (all columns) */
null,null,null,null,null
);
while(csr.moveToNext()) {
Log.d(
"TABLE1V1INFO",
"StartTime = " + csr.getString(csr.getColumnIndex(START_TIME_COLUMN))
);
}
}
@SuppressLint("Range")
public void logTable1V2() {
Cursor csr = db.query(TABLE1_NAME,
null, /* (all columns) */
null,null,null,null,null
);
DatabaseUtils.dumpCursor(csr);
while(csr.moveToNext()) {
Log.d(
"TABLE1V2INFO",
"StartTime = " + csr.getString(csr.getColumnIndex(START_TIME_COLUMN)) +
" AS INTEGER(Long)" + csr.getLong(csr.getColumnIndex(START_TIME_INT_COLUMN))
);
}
}
}
- 注意 3 logTable??一种用于table1的V1,一种用于table1的V2,一种用于table2的方法。
这是 Activity 中的代码,即打开数据库的 MainActivity,在版本为 1 时将一些行插入 table1 和 table2,每个表的行相同。如果版本为 1,则使用 logTableV1 方法将数据写入日志。如果版本为 2,则使用 logTableV2 将表写入具有新 start_time_int 值的日志。
在这两种情况下,logTable2 方法都会写入 start_time 和 start_time_int,后者已在 SQL 中动态生成。
结果
运行 1 - 使用版本 1 进行新安装:-
2021-10-23 08:10:33.974 D/TABLE1V1INFO: StartTime = 2021-10-01 10:25
2021-10-23 08:10:33.974 D/TABLE1V1INFO: StartTime = 2021-10-02 11:15
2021-10-23 08:10:33.975 D/TABLE2INFO: StartTime = 2021-10-01 10:25 AS INTEGER(long) 1633083900
2021-10-23 08:10:33.975 D/TABLE2INFO: StartTime = 2021-10-02 11:15 AS INTEGER(long) 1633173300
运行 2 - 版本更改为 2:-
2021-10-23 08:15:23.944 D/TABLE1V2INFO: StartTime = 2021-10-01 10:25 AS INTEGER(Long)1633083900
2021-10-23 08:15:23.944 D/TABLE1V2INFO: StartTime = 2021-10-02 11:15 AS INTEGER(Long)1633173300
2021-10-23 08:15:23.945 D/TABLE2INFO: StartTime = 2021-10-01 10:25 AS INTEGER(long) 1633083900
2021-10-23 08:15:23.945 D/TABLE2INFO: StartTime = 2021-10-02 11:15 AS INTEGER(long) 1633173300
如前所述,start_time 的格式很重要,如果不是 YYYY-MM-DD hh:mm,则可能需要对上述内容进行更改。但是,动态提取重新格式化的数据或更改表然后更新的原则适用。
您不妨考虑阅读SQLite - Date and Time Functions