我希望能够在SQLite数据库中添加或删除列。
我正在使用以下查询来删除列。
ALTER TABLE TABLENAME DROP COLUMN COLUMNNAME
但是它会报错
System.Data.SQLite.SQLiteException: SQLite error
near "DROP": syntax error
我希望能够在SQLite数据库中添加或删除列。
我正在使用以下查询来删除列。
ALTER TABLE TABLENAME DROP COLUMN COLUMNNAME
但是它会报错
System.Data.SQLite.SQLiteException: SQLite error
near "DROP": syntax error
SQLite仅支持有限的ALTER TABLE子集。在SQLite中,ALTER TABLE命令允许用户重命名表或向现有表添加新列。无法重命名列、删除列或向表添加或删除约束。
您可以:
PRAGMA foreign_keys=OFF
。在执行完这个序列后,为了重新启用外键,必须调用PRAGMA foreign_keys=ON
。 - PazOSQLite 3.35.0引入了ALTER TABLE DROP COLUMN
支持。
DROP COLUMN语法用于从表中删除现有列。 DROP COLUMN命令从表中删除指定的列,并重写整个表以清除与该列相关联的数据。 DROP COLUMN命令仅在该列未被模式的任何其他部分引用且不是PRIMARY KEY并且没有UNIQUE约束时才起作用。
以下语法将是有效的:
ALTER TABLE <TABLENAME> DROP COLUMN <COLUMNNAME>;
ALTER TABLE <TABLENAME> DROP <COLUMNNAME>;
我已经按照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;");
}
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/
INSERT
语句插入数据之外,你还可以通过执行"CREAT TABLE" + tableName + "AS SELECT " + columnsSeperated + " FROM " + tableName + "_old;"
的方式创建新表。 - Robert正如其他人所指出的那样
无法重命名列、删除列或添加/删除表的约束。
来源:http://www.sqlite.org/lang_altertable.html
虽然您可以始终创建一个新表,然后删除旧表。我将尝试通过一个示例来说明这个解决方法。
sqlite> .schema
CREATE TABLE person(
id INTEGER PRIMARY KEY,
first_name TEXT,
last_name TEXT,
age INTEGER,
height INTEGER
);
sqlite> select * from person ;
id first_name last_name age height
---------- ---------- ---------- ---------- ----------
0 john doe 20 170
1 foo bar 25 171
现在您想从这张表中删除列height
。
创建另一张名为new_person
的表。
sqlite> CREATE TABLE new_person(
...> id INTEGER PRIMARY KEY,
...> first_name TEXT,
...> last_name TEXT,
...> age INTEGER
...> ) ;
sqlite>
现在从旧表中复制数据。sqlite> INSERT INTO new_person
...> SELECT id, first_name, last_name, age FROM person ;
sqlite> select * from new_person ;
id first_name last_name age
---------- ---------- ---------- ----------
0 john doe 20
1 foo bar 25
sqlite>
现在删除 person
表,并将 new_person
重命名为 person
sqlite> DROP TABLE IF EXISTS person ;
sqlite> ALTER TABLE new_person RENAME TO person ;
sqlite>
现在,如果您执行.schema
命令,您将看到
sqlite>.schema
CREATE TABLE "person"(
id INTEGER PRIMARY KEY,
first_name TEXT,
last_name TEXT,
age INTEGER
);
SQLite数据库浏览器 允许您添加或删除列。
在主视图中的 Database Structure 选项卡中,单击表名。一个名为 Modify Table 的按钮将会启用,点击它会打开一个新窗口,您可以在其中选择要删除的列/字段。
曾经,SQLite并不直接支持此功能。您需要按照四个步骤操作:(1)创建临时表,(2)复制数据,(3)删除旧表,然后(4)重命名临时表。
但现在这些特性已经得到支持,您只需要升级SQLite即可。
ALTER TABLE DROP COLUMN
ALTER TABLE RENAME COLUMN
ALTER TABLE ADD COLUMN
请注意,仍然存在一些边缘情况可能不起作用,例如,您无法删除主键列。有关详细信息,请参阅文档。当这些ALTER TABLE … COLUMN
语句不起作用时,您可以回退到四个步骤的方法。
顺便说一下,文档中的四步过程实际上是12个步骤。但其中有4个步骤非常重要,容易出错,并且在文档中特别提到。
http://www.sqlite.org/lang_altertable.html
如图所示,仅支持ADD COLUMN。但是有一个(有点复杂的)解决方法:http://www.sqlite.org/faq.html#q11
我改进了user2638929的回答,现在它可以保留列类型、主键、默认值等。
public static void dropColumns(SQLiteDatabase database, String tableName, Collection<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.rawQuery(query,null);
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 + ");");
database.execSQL("INSERT INTO " + tableName + " (" + columnNamesSeparated + ") SELECT "
+ columnNamesSeparated + " FROM " + tableName + "_old;");
database.execSQL("DROP TABLE " + tableName + "_old;");
database.setTransactionSuccessful();
}finally {
database.endTransaction();
}
}
PS. 我在这里使用了 android.arch.persistence.db.SupportSQLiteDatabase
,但是您可以轻松地修改它以使用 android.database.sqlite.SQLiteDatabase
defaultValueType
因某些原因变成了String类型,而不是Integer类型。最好避免使用cursor.getType(cursor.getColumnIndex("dflt_value"))
。 - android developerimport re
import random
def DROP_COLUMN(db, table, column):
columns = [ c[1] for c in db.execute("PRAGMA table_info(%s)" % table) ]
columns = [ c for c in columns if c != column ]
sql = db.execute("SELECT sql from sqlite_master where name = '%s'"
% table).fetchone()[0]
sql = format(sql)
lines = sql.splitlines()
findcol = r'\b%s\b' % column
keeplines = [ line for line in lines if not re.search(findcol, line) ]
create = '\n'.join(keeplines)
create = re.sub(r',(\s*\))', r'\1', create)
temp = 'tmp%d' % random.randint(1e8, 1e9)
db.execute("ALTER TABLE %(old)s RENAME TO %(new)s" % {
'old': table, 'new': temp })
db.execute(create)
db.execute("""
INSERT INTO %(new)s ( %(columns)s )
SELECT %(columns)s FROM %(old)s
""" % {
'old': temp,
'new': table,
'columns': ', '.join(columns)
})
db.execute("DROP TABLE %s" % temp)
def format(sql):
sql = sql.replace(",", ",\n")
sql = sql.replace("(", "(\n")
sql = sql.replace(")", "\n)")
return sql