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方法,有可能一个月,有可能一年。查找成本也很高。
更多相关文章
- OpenCV4Android开发之旅(一)----OpenCV2.4简介及 app通过Java接
- 在android中使用OrmLite数据库框架
- Android平台调用WebService详解
- Android-sharedUserId
- Android下创建一个sqlite数据库
- Android下Content Provider使用
- 如何将android SDK sample中的例子添加到eclipse中
- Android开发学习系列-----开发环境准备
- Android个版本适配之7.0