SQLite 数据库迁移以将数据复制、解析和粘贴到另一列
SQLite DB migration to copy, parse and paste data to another column
我有一个名为 start_time
的列,它是 my_table
中的字符串类型。我想创建一个名为 start_time_int
的附加列(附加的,因为项目的某些部分需要 String 类型,而有些部分使用 int 类型会做得更好)我从 start_time
复制所有值,将它们解析为 long 并将它们粘贴到 start_time_int
。仅使用 SQL 命令就可以进行这种迁移吗?
Is this sort of migration possible with just SQL commands?
是的,至少可以达到最终结果。
但是,start_time 的格式很重要。
此外,可能不需要迁移,因为很可能 start_time 的格式很重要,动态转换结果并且不存储相同的信息两次。
假设 start_time 的格式为 YYYY-MM-DD hh:mm 例如2021-10-01 10:25 然后由于格式是 SQLite 识别的格式,您可以在查询 table 时使用 strftime('%s',start_time) AS start_time_int
获得长版本,并且会有 start_time_int 列,它是一个 INTEGER(长)。
这是一个演示应用程序,它显示了基于上述格式的 start_time 的两种技术。
数据库有两个 tables table1 和 table2 最初具有相同的架构 _id 列和 start_time 列。
当数据库版本从 1 增加到 2 时,通过 [=56] 在 onUpgrade
方法中添加一个额外的列 start_time_int =]ALTER TABLE table1 ADD COLUMN start_time_int INTEGER
,后面跟着一个 UPDATE table1 SET start_time_int = strftime('%s',start_time) WHERE start_time_int IS NULL;
这个设置 start_time_int 值(因为在 start_time_int 列定义中没有指定 DEFAULT 被设置为空)。
- 请注意,为了迎合新安装,
onCreate
版本也已更改。由于此演示旨在测试版本之间的切换,因此 onCreate
方法具有应用相应 table 创建的逻辑。
但是,table2 保持不变。这个table是用来说明不需要更改table,因为Long值很容易被提取出来。
数据库助手(扩展SQLiteOpenHelper的class)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 打开数据库,将一些行插入 table1 和 table2 当版本为 1 时,每个 table 的行相同。如果版本为 1,则使用 logTableV1
方法将数据写入日志。如果版本为 2,则 logTableV2
用于使用新的 start_time_int 值将 table 写入日志。
在这两种情况下,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,则对上述内容进行更改可能需要。但是,动态提取重新格式化的数据或更改 table 然后更新的原则适用。
我有一个名为 start_time
的列,它是 my_table
中的字符串类型。我想创建一个名为 start_time_int
的附加列(附加的,因为项目的某些部分需要 String 类型,而有些部分使用 int 类型会做得更好)我从 start_time
复制所有值,将它们解析为 long 并将它们粘贴到 start_time_int
。仅使用 SQL 命令就可以进行这种迁移吗?
Is this sort of migration possible with just SQL commands?
是的,至少可以达到最终结果。
但是,start_time 的格式很重要。
此外,可能不需要迁移,因为很可能 start_time 的格式很重要,动态转换结果并且不存储相同的信息两次。
假设 start_time 的格式为 YYYY-MM-DD hh:mm 例如2021-10-01 10:25 然后由于格式是 SQLite 识别的格式,您可以在查询 table 时使用 strftime('%s',start_time) AS start_time_int
获得长版本,并且会有 start_time_int 列,它是一个 INTEGER(长)。
这是一个演示应用程序,它显示了基于上述格式的 start_time 的两种技术。
数据库有两个 tables table1 和 table2 最初具有相同的架构 _id 列和 start_time 列。
当数据库版本从 1 增加到 2 时,通过 [=56] 在 onUpgrade
方法中添加一个额外的列 start_time_int =]ALTER TABLE table1 ADD COLUMN start_time_int INTEGER
,后面跟着一个 UPDATE table1 SET start_time_int = strftime('%s',start_time) WHERE start_time_int IS NULL;
这个设置 start_time_int 值(因为在 start_time_int 列定义中没有指定 DEFAULT 被设置为空)。
- 请注意,为了迎合新安装,
onCreate
版本也已更改。由于此演示旨在测试版本之间的切换,因此onCreate
方法具有应用相应 table 创建的逻辑。
但是,table2 保持不变。这个table是用来说明不需要更改table,因为Long值很容易被提取出来。
数据库助手(扩展SQLiteOpenHelper的class)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 打开数据库,将一些行插入 table1 和 table2 当版本为 1 时,每个 table 的行相同。如果版本为 1,则使用 logTableV1
方法将数据写入日志。如果版本为 2,则 logTableV2
用于使用新的 start_time_int 值将 table 写入日志。
在这两种情况下,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,则对上述内容进行更改可能需要。但是,动态提取重新格式化的数据或更改 table 然后更新的原则适用。