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

问题描述 投票:0回答:1

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

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

通过复制到新表,我设法很好地删除了这些列,但是由于缺少foreignKeysindices,所以迁移不起作用,这样做的干净语法是什么?

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

 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();
    }
}
android android-sqlite database-migration android-room
1个回答
0
投票

我无法复制外键和索引

对于外键,您可以根据PRAGMA foreign_keys_list(the_table)的输出来生成它们,这些输出会生成诸如:-]之类的输出>

PRAGMA foreign_keys_list(the_table)

对于indicies

,您可以基于enter image description here的输出来生成它们,以获取索引名称并检查UNIQUE约束。

PRAGMA index_list(the_table)

使用索引名称,然后可以使用PRAGMA index_list(the_table)

enter image description here

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

PRAGMA index_info(the_index_name)

一种替代方法,可能比尝试满足所有排列的方法更简单]]

  • a)更改实体,然后
  • b)从@Database的_impl生成的代码中获取SQL。例如上面的代码已经成功地通过简单的1列删除,2个FK和覆盖两个映射列的索引成功进行了测试,抓取了以下可能使用过的蜜蜂
  • :-

PRAGMA index_info(the_index_name)
  • 因为SQL是为您编写的。这只是创建ALTER,INSERT和DROP SQL的问题。

    以上与运行以上命令的Logged SQL相比:-

enter image description here

免责声明

以上内容并不能满足所有情况,仅用于说明基本技术。该代码确实包含有关限制的注释。但是,还有其他考虑因素,例如部分索引以及WHERE子句,FTS和FK的MATCH列。

© www.soinside.com 2019 - 2024. All rights reserved.