Android 复制表后的迁移问题,如何同时复制索引和外键?

Android 复制表后的迁移问题,如何同时复制索引和外键?,android,android-sqlite,database-migration,android-room,Android,Android Sqlite,Database Migration,Android Room,我需要从非常大的roomDB(SQLite)表中删除一些列 据我所知,我无法从现有表中删除列,为此,我需要创建一个新表并复制所需的列(我们要删除的列除外) 通过复制到新表,我成功地删除了这些列,但迁移不起作用,因为缺少foreignKeys和index,什么是干净的语法 这是我在迁移中用于删除某些列的方法: private static void deleteColumns(SupportSQLiteDatabase database, String tableName, List<St

我需要从非常大的roomDB(SQLite)表中删除一些列

据我所知,我无法从现有表中删除列,为此,我需要创建一个新表并复制所需的列(我们要删除的列除外)

通过复制到新表,我成功地删除了这些列,但迁移不起作用,因为缺少foreignKeysindex,什么是干净的语法

这是我在迁移中用于删除某些列的方法:

 private static void deleteColumns(SupportSQLiteDatabase database, String tableName, List<String> columnsToRemove){
    List<String> columnNames = new ArrayList<>();
    List<String> columnNamesWithType = new ArrayList<>();
    List<String> primaryKeys = new ArrayList<>();
    String query = "pragma table_info(" + tableName + ");";

    Cursor cursor = database.query(query);
    while (cursor.moveToNext()){
        String columnName = cursor.getString(cursor.getColumnIndex("name"));

        if (columnsToRemove.contains(columnName)){
            continue;
        }

        String columnType = cursor.getString(cursor.getColumnIndex("type"));
        boolean isNotNull = cursor.getInt(cursor.getColumnIndex("notnull")) == 1;
        boolean isPk = cursor.getInt(cursor.getColumnIndex("pk")) == 1;

        columnNames.add(columnName);
        String tmp = "`" + columnName + "` " + columnType + " ";
        if (isNotNull){
            tmp += " NOT NULL ";
        }

        int defaultValueType = cursor.getType(cursor.getColumnIndex("dflt_value"));
        if (defaultValueType == Cursor.FIELD_TYPE_STRING){
            tmp += " DEFAULT " + "\"" + cursor.getString(cursor.getColumnIndex("dflt_value")) + "\" ";
        }else if(defaultValueType == Cursor.FIELD_TYPE_INTEGER){
            tmp += " DEFAULT " + cursor.getInt(cursor.getColumnIndex("dflt_value")) + " ";
        }else if (defaultValueType == Cursor.FIELD_TYPE_FLOAT){
            tmp += " DEFAULT " + cursor.getFloat(cursor.getColumnIndex("dflt_value")) + " ";
        }
        columnNamesWithType.add(tmp);
        if (isPk){
            primaryKeys.add("`" + columnName + "`");
        }
    }
    cursor.close();

    String columnNamesSeparated = TextUtils.join(", ", columnNames);
    if (primaryKeys.size() > 0){
        columnNamesWithType.add("PRIMARY KEY("+ TextUtils.join(", ", primaryKeys) +")");
    }
    String columnNamesWithTypeSeparated = TextUtils.join(", ", columnNamesWithType);

    database.beginTransaction();
    try {
        database.execSQL("ALTER TABLE " + tableName + " RENAME TO " + tableName + "_old;");
        database.execSQL("CREATE TABLE " + tableName + " (" + columnNamesWithTypeSeparated + ") + FOREIGN KEY +(trackartist) REFERENCES artist(artistid) ;" );
        database.execSQL("INSERT INTO " + tableName + " (" + columnNamesSeparated + ") SELECT "
                + columnNamesSeparated + " FROM " + tableName + "_old;");
        database.execSQL("DROP TABLE " + tableName + "_old;");
        database.setTransactionSuccessful();
    }finally {
        database.endTransaction();
    }
}
private static void deleteColumns(SupportSQLiteDatabase数据库、String tableName、List columnsToRemove){
List columnNames=新建ArrayList();
List columnNamesWithType=new ArrayList();
List primaryKeys=new ArrayList();
String query=“pragma table_info(“+tableName+”)”;
Cursor=database.query(查询);
while(cursor.moveToNext()){
String columnName=cursor.getString(cursor.getColumnIndex(“名称”));
if(columnsToRemove.contains(columnName)){
继续;
}
String columnType=cursor.getString(cursor.getColumnIndex(“type”);
布尔值isNotNull=cursor.getInt(cursor.getColumnIndex(“notnull”))==1;
布尔值isPk=cursor.getInt(cursor.getColumnIndex(“pk”))=1;
columnNames.add(columnName);
字符串tmp=“`+columnName+”`+columnType+”;
if(isNotNull){
tmp+=“非空”;
}
int defaultValueType=cursor.getType(cursor.getColumnIndex(“dflt_值”);
if(defaultValueType==游标.字段类型字符串){
tmp++=“默认值”+“\”+游标.getString(游标.getColumnIndex(“dflt\U值”))+“\”;
}else if(defaultValueType==Cursor.FIELD\u TYPE\u INTEGER){
tmp++=“DEFAULT”+cursor.getInt(cursor.getColumnIndex(“dflt_值”)+”;
}else if(defaultValueType==游标.字段\u类型\u浮点){
tmp+=“DEFAULT”+cursor.getFloat(cursor.getColumnIndex(“dflt_值”))+“”;
}
columnNamesWithType.add(tmp);
如果(isPk){
添加(“`”+columnName+“`”);
}
}
cursor.close();
字符串columnNamesSeparated=TextUtils.join(“,”,columnNames);
if(primaryKeys.size()>0){
columnNamesWithType.add(“主键(“+TextUtils.join”(“,”,primaryKeys)+”);
}
字符串columnNamesWithTypeSeparated=TextUtils.join(“,”,columnNamesWithType);
database.beginTransaction();
试一试{
execSQL(“altertable”+tableName+“重命名为”+tableName+“_old;”);
execSQL(“创建表”+tableName+”(“+columnnamwithtypeseparated+”)+外键+(trackartist)引用艺术家(artistid);”;
execSQL(“插入到“+tableName+”(“+columnNamesSeparated+”)选择”
+ColumnNames从“+tableName+”中分离出+”;
execSQL(“DROP TABLE”+tableName+“_old;”);
database.setTransactionSuccessful();
}最后{
数据库。endTransaction();
}
}
我不能复制外键和索引

对于外键,您可以根据产生输出的输出生成外键,例如:-

对于标记您可以根据的输出生成标记,以获取索引名并检查唯一约束

然后可以使用索引名

例如,对代码的以下修改将起作用(关于限制的注释):-

  • 因为SQL是为您编写的。接下来就是创建ALTER、INSERT和DROP SQL的问题
上述内容与运行上述内容记录的SQL进行比较:-

2019-10-12 15:01:34.242 D/ALTERSQL: ALTER TABLE table1 RENAME TO table1_old;
2019-10-12 15:01:34.242 D/CREATESQL: CREATE TABLE table1 (`id` INTEGER , `name` TEXT , `mapToTable2` INTEGER  NOT NULL , `mapToTable3` INTEGER  NOT NULL , PRIMARY KEY(`id`),FOREIGN KEY (mapToTable3) REFERENCES `table3`(id)  ON DELETE NO ACTION ON UPDATE NO ACTION,FOREIGN KEY (mapToTable2) REFERENCES `table2`(id)  ON DELETE NO ACTION ON UPDATE NO ACTION)
2019-10-12 15:01:34.242 D/INSERTSQL: INSERT INTO table1 (id, name, mapToTable2, mapToTable3) SELECT id, name, mapToTable2, mapToTable3 FROM table1_old;
2019-10-12 15:01:34.242 D/DROPSQL: DROP TABLE table1_old;
2019-10-12 15:01:34.242 D/CREATEINDEXSQL: CREATE  INDEX IF NOT EXISTS `index_table1_mapToTable2_mapToTable3` ON `table1`(`mapToTable2`,`mapToTable3`);
免责声明 上述内容并不适用于所有情况,仅用于演示基本技术。代码中确实包含一些关于限制的注释。但是,还有其他考虑因素,例如部分索引和WHERE子句、FTS和FK的匹配列

我不能复制外键和索引

对于外键,您可以根据产生输出的输出生成外键,例如:-

对于标记您可以根据的输出生成标记,以获取索引名并检查唯一约束

然后可以使用索引名

例如,对代码的以下修改将起作用(关于限制的注释):-

  • 因为SQL是为您编写的。接下来就是创建ALTER、INSERT和DROP SQL的问题
上述内容与运行上述内容记录的SQL进行比较:-

2019-10-12 15:01:34.242 D/ALTERSQL: ALTER TABLE table1 RENAME TO table1_old;
2019-10-12 15:01:34.242 D/CREATESQL: CREATE TABLE table1 (`id` INTEGER , `name` TEXT , `mapToTable2` INTEGER  NOT NULL , `mapToTable3` INTEGER  NOT NULL , PRIMARY KEY(`id`),FOREIGN KEY (mapToTable3) REFERENCES `table3`(id)  ON DELETE NO ACTION ON UPDATE NO ACTION,FOREIGN KEY (mapToTable2) REFERENCES `table2`(id)  ON DELETE NO ACTION ON UPDATE NO ACTION)
2019-10-12 15:01:34.242 D/INSERTSQL: INSERT INTO table1 (id, name, mapToTable2, mapToTable3) SELECT id, name, mapToTable2, mapToTable3 FROM table1_old;
2019-10-12 15:01:34.242 D/DROPSQL: DROP TABLE table1_old;
2019-10-12 15:01:34.242 D/CREATEINDEXSQL: CREATE  INDEX IF NOT EXISTS `index_table1_mapToTable2_mapToTable3` ON `table1`(`mapToTable2`,`mapToTable3`);
免责声明
上述内容并不适用于所有情况,仅用于演示基本技术。代码中确实包含一些关于限制的注释。但是,还有其他注意事项,例如部分索引和WHERE子句、FTS和FK的匹配列。

请编辑您的问题,以包括前后模式(迁移中使用的实体和create table语句)。简言之,更改的表必须与实体将生成的架构相匹配。谢谢,我根据您的要求进行了更新,我知道更改的表必须与架构相匹配,发生错误的原因是我无法复制foreignkey和indicate。请编辑您的问题以包括前后架构(迁移中使用的实体和create table语句)。简言之,修改后的表必须与实体使用的架构相匹配将生成。谢谢,我按照您的要求进行了更新,我知道更改后的表必须与架构匹配,发生错误是因为我无法复制外键和索引。谢谢您的帮助!谢谢
2019-10-12 15:01:34.242 D/ALTERSQL: ALTER TABLE table1 RENAME TO table1_old;
2019-10-12 15:01:34.242 D/CREATESQL: CREATE TABLE table1 (`id` INTEGER , `name` TEXT , `mapToTable2` INTEGER  NOT NULL , `mapToTable3` INTEGER  NOT NULL , PRIMARY KEY(`id`),FOREIGN KEY (mapToTable3) REFERENCES `table3`(id)  ON DELETE NO ACTION ON UPDATE NO ACTION,FOREIGN KEY (mapToTable2) REFERENCES `table2`(id)  ON DELETE NO ACTION ON UPDATE NO ACTION)
2019-10-12 15:01:34.242 D/INSERTSQL: INSERT INTO table1 (id, name, mapToTable2, mapToTable3) SELECT id, name, mapToTable2, mapToTable3 FROM table1_old;
2019-10-12 15:01:34.242 D/DROPSQL: DROP TABLE table1_old;
2019-10-12 15:01:34.242 D/CREATEINDEXSQL: CREATE  INDEX IF NOT EXISTS `index_table1_mapToTable2_mapToTable3` ON `table1`(`mapToTable2`,`mapToTable3`);