SQlite字段类型升级

一、升级SQlite字段类型

推荐一个SQLite工具SQliteBrowser
在Android项目开发过程中,总会使用数据库,Android上主要使用的是SQlite。
但是SQlite是一个轻量级的数据库,提供的功能是有限的。
新的需求是修改字段的类型

如果是普通的sql可以使用

alter table 表名
alter column 字段名 字段类型

但是在SQlite中alter命令只支持修改表名和增加新列这里

那么方案应该是:
1、将原来的表重命名:name_temp
2、新建一个表name,该表中已经修改过字段名
3、将name_temp中的数据拷贝到name中
4、将temp表删除

聚个栗子:
正常的创建并插入数据:
1、创建表:

CREATE TABLE `student` (
    `name`  TEXT,
    `age`   TEXT
);

2.插入数据

insert into student values("shang",25)

当前表的内容
这里写图片描述

现在发现age的类型是text,想要Integer类型。
1、rename

alter table student rename to student_temp;

2、创建新的表student,age字段类型是INTEGER

CREATE TABLE student (
`name`  TEXT,
`age`   INTEGER
);

3、将temp中的数据拷贝到student表中

insert into student select name, age from student_temp;

4、把temp表删除掉

drop table student_temp

完成。

二、数据库升级中的坑

但是在数据库升级时候会有坑
数据库版本是2的代码:
相对于版本1做的升级是讲age字段的类型从TEXT改为INTEGER。

//创建新表
private void createTables(SQLiteDatabase db) {
        try {
        String createStr = "CREATE TABLE `student` (
    `name`  TEXT,`age`  INTEGER);";
        db.execSQL(createStr);
        } catch (Exception ex) {

        }
    }
    //数据库升级
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        try {
            switch (oldVersion) {
            case 1:
                student1to2(db);
                // 刻意进行穿透。 按序升级
            default:
                break;
            }
        } catch (Exception ex) {
            createTables(db);
        }
    }
    public void student1to2(db){
        //1、重命名
        String renameStr = "alter table student rename to student_temp;";
        db.execSQL(renameStr);
        //2、创建新的表
        createTables(db);
        //3、拷贝
        String copyStr = "insert into student select name, age from student_temp;";
        db.execSQL(copyStr);
        //4、删除表
        String dropStr = "drop table student_temp";
        db.execSQL(dropStr);
    }

数据库版本是3的代码:
相对于2变化的是增加一列school

//创建新表
private void createTables(SQLiteDatabase db) {
        try {
        String createStr = "CREATE TABLE `student` (
    `name`  TEXT,`age`  INTEGER,`school`     TEXT);";
        db.execSQL(createStr);
        } catch (Exception ex) {

        }
    }
    //数据库升级
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        try {
            switch (oldVersion) {
            case 1:
                student1to2(db);
                // 刻意进行穿透。 按序升级
            case 2:
                student2to3(db);
                // 刻意进行穿透。 按序升级
            default:
                break;
            }
        } catch (Exception ex) {
            createTables(db);
        }
    }
    public void student1to2(SQLiteDatabase db){
        //1、重命名
        String renameStr = "alter table student rename to student_temp;";
        db.execSQL(renameStr);
        //2、创建新的表
        createTables(db);
        //3、拷贝
        String copyStr = "insert into student select name, age from student_temp;";
        db.execSQL(copyStr);
        //4、删除表
        String dropStr = "drop table student_temp";
        db.execSQL(dropStr);
    }

    public void student2to3(SQLiteDatabase db) {
        String sql = "ALTER TABLE student ADD COLUMN school TEXT;"
        db.execSQL(sql);
    }

如果用户的安装app的版本依次是1,2,3,则没有错。

如果用户的APP版本是1直接跳到3,则会出错。
出问题的原因是app启动会检测当前正在使用的数据库版本(1),即将升级的版本(3),数据库需要升级,可以看到onUpgrade方法中不支持1直接升级到3,而是1-2-3升级,在student1to2中使用了createTables,而在3中createTables已经对student的表增加一列(school),则会错误如下:

table student has 3 columns but 2 values were supplied: 
insert into student select name, age from student_temp;

有人会问,如果2升级到3是减少一列(age),是否会出问题那?答案是依然会出问题,错误:

table student has 1 columns but 2 values were supplied: 
insert into student select name, age from student_temp;

可能有人会说可以使用以下代码进行复制:

insert into student(name, age) select name, age from student_temp;

新表是增加一列(school)的话,没有问题;
如果新表去掉一列,继续使用上述的语句,则会出现下面错误:

table student has no column named age: 
insert into student(name, age) select name, age from student_temp

正确的处理方法是有一个createTables方法,还有一个createTables1to2的方法,在数据库版本是2的时候,这两个方法是完全一样的,在数据库版本升级到3时候,只需要修改createTables方法,而不修改createTables1to2的内容,createTables1to2是从1升级到2专用的方法。

正确的版本3的代码应该是:

//创建新表
private void createTables(SQLiteDatabase db) {
        try {
        String createStr = "CREATE TABLE `student` (
    `name`  TEXT,`age`  INTEGER,`school`     TEXT);";
        db.execSQL(createStr);
        } catch (Exception ex) {

        }
    }
//数据库升级
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        try {
            switch (oldVersion) {
            case 1:
                student1to2(db);
                // 刻意进行穿透。 按序升级
            case 2:
                student2to3(db);
            default:
                break;
            }
        } catch (Exception ex) {
            createTables(db);
        }
    }

    public void student1to2(SQLiteDatabase db){
        //1、重命名
        String renameStr = "alter table student rename to student_temp;";
        db.execSQL(renameStr);
        //2、创建新的表
        createTables(db);
        //3、拷贝
        String copyStr = "insert into student select name, age from student_temp;";
        db.execSQL(copyStr);
        //4、删除表
        String dropStr = "drop table student_temp";
        db.execSQL(dropStr);
    }

    public void student2to3(SQLiteDatabase db) {
        String sql = "ALTER TABLE student ADD COLUMN school TEXT;"
     db.execSQL(sql);

    //1到2升级专用
    public void createTables1to2(SQLiteDatabase db){
    try {
        String createStr = "CREATE TABLE `student` (
    `name`  TEXT,`age`  INTEGER);";
        db.execSQL(createStr);
        } catch (Exception ex) {

        }
}

这个bug出现的出现取决于什么时候修改createTables方法,有可能一个月,有可能一年。查找成本也很高。

你可能感兴趣的:(android)