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 table1table2 最初具有相同的架构 _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 然后更新的原则适用。

您不妨考虑阅读SQLite - Date and Time Functions