我想在sqlite数据库中删除或添加列

我正在使用以下查询删除列。

ALTER TABLE TABLENAME DROP COLUMN COLUMNNAME

但它会产生错误

System.Data.SQLite.SQLiteException: SQLite error
near "DROP": syntax error

当前回答

我根据Sqlite推荐的方法写了一个Java实现:

private void dropColumn(SQLiteDatabase db,
        ConnectionSource connectionSource,
        String createTableCmd,
        String tableName,
        String[] colsToRemove) throws java.sql.SQLException {

    List<String> updatedTableColumns = getTableColumns(tableName);
    // Remove the columns we don't want anymore from the table's list of columns
    updatedTableColumns.removeAll(Arrays.asList(colsToRemove));

    String columnsSeperated = TextUtils.join(",", updatedTableColumns);

    db.execSQL("ALTER TABLE " + tableName + " RENAME TO " + tableName + "_old;");

    // Creating the table on its new format (no redundant columns)
    db.execSQL(createTableCmd);

    // Populating the table with the data
    db.execSQL("INSERT INTO " + tableName + "(" + columnsSeperated + ") SELECT "
            + columnsSeperated + " FROM " + tableName + "_old;");
    db.execSQL("DROP TABLE " + tableName + "_old;");
}

为了获得表的列,我使用了“PRAGMA table_info”:

public List<String> getTableColumns(String tableName) {
    ArrayList<String> columns = new ArrayList<String>();
    String cmd = "pragma table_info(" + tableName + ");";
    Cursor cur = getDB().rawQuery(cmd, null);

    while (cur.moveToNext()) {
        columns.add(cur.getString(cur.getColumnIndex("name")));
    }
    cur.close();

    return columns;
}

实际上我在我的博客上写过,你可以在那里看到更多的解释:

http://udinic.wordpress.com/2012/05/09/sqlite-drop-column-support/

其他回答

public void DeleteColFromTable(String DbName, String TableName, String ColName){
    SQLiteDatabase db = openOrCreateDatabase(""+DbName+"", Context.MODE_PRIVATE, null);
    db.execSQL("CREATE TABLE IF NOT EXISTS "+TableName+"(1x00dff);");
    Cursor c = db.rawQuery("PRAGMA table_info("+TableName+")", null);
    if (c.getCount() == 0) {

    } else {
        String columns1 = "";
        String columns2 = "";
        while (c.moveToNext()) {
            if (c.getString(1).equals(ColName)) {
            } else {
                columns1 = columns1 + ", " + c.getString(1) + " " + c.getString(2);
                columns2 = columns2 + ", " + c.getString(1);
            }
            if (c.isLast()) {
                db.execSQL("CREATE TABLE IF NOT EXISTS DataBackup (" + columns1 + ");");
                db.execSQL("INSERT INTO DataBackup SELECT " + columns2 + " FROM "+TableName+";");
                db.execSQL("DROP TABLE "+TableName+"");
                db.execSQL("ALTER TABLE DataBackup RENAME TO "+TableName+";");
            }
        }
    }
}

只需要调用一个方法

DeleteColFromTable("Database name","Table name","Col name which want to delete");

Kotlin解决方案,基于这里,还要:

确保临时表不存在 修复了检查默认值的类型,因为当它是Integer时返回String类型(此处报告了此问题)。 避免在希望删除的列不存在时执行任何操作。

object DbUtil {
    /** https://stackoverflow.com/a/51587449/878126 */
    @JvmStatic
    fun dropColumns(database: SQLiteDatabase, tableName: String,
        columnsToRemove: Collection<String>) {
        val columnNames: MutableList<String> = ArrayList()
        val columnNamesWithType: MutableList<String> = ArrayList()
        val primaryKeys: MutableList<String> = ArrayList()
        val query = "pragma table_info($tableName);"
        val cursor = database.rawQuery(query, null)
        val columnDefaultIndex = cursor.getColumnIndex("dflt_value")
        val columnNameIndex = cursor.getColumnIndex("name")
        val columnTypeIndex = cursor.getColumnIndex("type")
        val columnNotNullIndex = cursor.getColumnIndex("notnull")
        val columnPrimaryKeyIndex = cursor.getColumnIndex("pk")
        val sb = StringBuilder()
        var foundColumnsToRemove = false
        while (cursor.moveToNext()) {
            val columnName = cursor.getString(columnNameIndex)
            if (columnsToRemove.contains(columnName)) {
                foundColumnsToRemove = true
                continue
            }
            val columnType = cursor.getString(columnTypeIndex)
            val isNotNull = cursor.getInt(columnNotNullIndex) == 1
            val isPrimaryKey = cursor.getInt(columnPrimaryKeyIndex) == 1
            columnNames.add(columnName)
            sb.clear()
            sb.append("`$columnName` $columnType ")
            if (isNotNull)
                sb.append(" NOT NULL ")
            if (cursor.getType(columnDefaultIndex) != Cursor.FIELD_TYPE_NULL) {
                //has default value
                when (columnType.uppercase()) {
                    "INTEGER" -> sb.append(" DEFAULT ${cursor.getInt(columnDefaultIndex)} ")
                    "TEXT" -> sb.append(" DEFAULT \"${cursor.getString(columnDefaultIndex)}\" ")
                    "REAL" -> sb.append(" DEFAULT ${cursor.getFloat(columnDefaultIndex)} ")
                }
            }
            columnNamesWithType.add(sb.toString())
            if (isPrimaryKey)
                primaryKeys.add("`$columnName`")
        }
        cursor.close()
        if (!foundColumnsToRemove)
            return
        val columnNamesSeparated = TextUtils.join(", ", columnNames)
        if (primaryKeys.size > 0)
            columnNamesWithType.add("PRIMARY KEY(${TextUtils.join(", ", primaryKeys)})")
        val columnNamesWithTypeSeparated = TextUtils.join(", ", columnNamesWithType)
        database.beginTransaction()
        try {
            var newTempTableName: String
            var counter = 0
            while (true) {
                newTempTableName = "${tableName}_old_$counter"
                if (!isTableExists(database, newTempTableName))
                    break
                ++counter
            }
            database.execSQL("ALTER TABLE $tableName RENAME TO $newTempTableName;")
            database.execSQL("CREATE TABLE $tableName ($columnNamesWithTypeSeparated);")
            database.execSQL(
                "INSERT INTO $tableName ($columnNamesSeparated) SELECT $columnNamesSeparated FROM $newTempTableName;")
            database.execSQL("DROP TABLE ${newTempTableName};")
            database.setTransactionSuccessful()
        } finally {
            database.endTransaction()
        }
    }

    @JvmStatic
    fun isTableExists(database: SQLiteDatabase, tableName: String): Boolean {
        database.rawQuery(
            "select DISTINCT tbl_name from sqlite_master where tbl_name = '$tableName'", null)
            ?.use {
                return it.count > 0
            } ?: return false
    }
}

你可以使用Sqlitebrowser。在浏览器模式下,对于各自的数据库和表,在选项卡-database结构下,选择Modify table后,可以删除各自的列。

作为替代:

如果有一个带模式的表

CREATE TABLE person(
  id INTEGER PRIMARY KEY,
  first_name TEXT,
  last_name TEXT,
  age INTEGER,
  height INTEGER
);

你可以使用CREATE TABLE…AS语句,如CREATE TABLE person2 AS SELECT id, first_name, last_name, age FROM person;,即去掉你不想要的列。然后删除原来的person表并重命名新表。

注意,此方法生成的表没有PRIMARY KEY,也没有约束。为了保留这些表,可以使用其他人描述的方法来创建新表,或者使用临时表作为中间表。

由于SQLite对ALTER TABLE的支持有限,所以你只能在表的末尾添加列或在SQLite中更改TABLE_NAME。

这里是如何从SQLITE删除列的最佳答案?

从SQLite表中删除列