Tôi muốn xóa hoặc thêm cột trong cơ sở dữ liệu sqlite
Tôi đang sử dụng truy vấn sau để xóa cột.
ALTER TABLE TABLENAME DROP COLUMN COLUMNNAME
Nhưng nó báo lỗi
System.Data.SQLite.SQLiteException: SQLite error
near "DROP": syntax error
Tôi muốn xóa hoặc thêm cột trong cơ sở dữ liệu sqlite
Tôi đang sử dụng truy vấn sau để xóa cột.
ALTER TABLE TABLENAME DROP COLUMN COLUMNNAME
Nhưng nó báo lỗi
System.Data.SQLite.SQLiteException: SQLite error
near "DROP": syntax error
Câu trả lời:
SQLite hỗ trợ một tập hợp con giới hạn của ALTER TABLE. Lệnh ALTER TABLE trong SQLite cho phép người dùng đổi tên bảng hoặc thêm cột mới vào bảng hiện có. Không thể đổi tên một cột, xóa một cột hoặc thêm hoặc xóa các ràng buộc khỏi một bảng.
Bạn có thể:
PRAGMA foreign_keys=OFF
. Trong trường hợp này, sau khi thực hiện chuỗi này, người ta phải gọi PRAGMA foreign_keys=ON
để kích hoạt lại khóa ngoại.
RENAME COLUMN
được hỗ trợ. 🎉 sqlite.org/releaselog/3_25_0.html
Tôi đã viết một triển khai Java dựa trên cách được đề xuất của Sqlite để làm điều này:
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;");
}
Để lấy cột của bảng, tôi đã sử dụng "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;
}
Tôi thực sự đã viết về nó trên blog của tôi, bạn có thể xem thêm lời giải thích ở đó:
http://udinic.wordpress.com/2012/05/09/sqlite-drop-column-support/
INSERT
tuyên bố, bạn cũng có thể tạo bảng mới bằng cách thực hiện"CREAT TABLE" + tableName + "AS SELECT " + columnsSeperated + " FROM " + tableName + "_old;"
Như những người khác đã chỉ ra
Không thể đổi tên một cột, xóa một cột hoặc thêm hoặc xóa các ràng buộc khỏi một bảng.
nguồn: http://www.sqlite.org/lang_altertable.html
Trong khi bạn luôn có thể tạo một bảng mới và sau đó thả bảng cũ hơn. Tôi sẽ cố gắng giải thích cách giải quyết này bằng một ví dụ.
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
Bây giờ bạn muốn xóa cột height
khỏi bảng này.
Tạo một bảng khác gọi là new_person
sqlite> CREATE TABLE new_person(
...> id INTEGER PRIMARY KEY,
...> first_name TEXT,
...> last_name TEXT,
...> age INTEGER
...> ) ;
sqlite>
Bây giờ sao chép dữ liệu từ bảng cũ
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>
Bây giờ Thả person
bảng và đổi tên new_person
thànhperson
sqlite> DROP TABLE IF EXISTS person ;
sqlite> ALTER TABLE new_person RENAME TO person ;
sqlite>
Vì vậy, bây giờ nếu bạn làm một .schema
, bạn sẽ thấy
sqlite>.schema
CREATE TABLE "person"(
id INTEGER PRIMARY KEY,
first_name TEXT,
last_name TEXT,
age INTEGER
);
CREATE TABLE new_person AS SELECT id, first_name, last_name, age FROM person;
http://www.sqlite.org/lang_altertable.html
Như bạn có thể thấy trong sơ đồ, chỉ hỗ trợ ADD COLUMN. Tuy nhiên, có một cách giải quyết (khá nặng): http://www.sqlite.org/faq.html#q11
Chúng tôi không thể bỏ một cột cụ thể trong SQLite 3. Xem Câu hỏi thường gặp .
Như những người khác đã chỉ ra, ALTER TABLE
tuyên bố của sqlite không hỗ trợ DROP COLUMN
và công thức chuẩn để làm điều này không bảo tồn các ràng buộc & chỉ số.
Đây là một số mã python để làm điều này một cách khái quát, trong khi vẫn duy trì tất cả các ràng buộc và chỉ số chính.
Vui lòng sao lưu cơ sở dữ liệu của bạn trước khi sử dụng! Hàm này dựa vào việc ghi lại câu lệnh CREATE TABLE ban đầu và có khả năng hơi không an toàn - ví dụ, nó sẽ làm sai nếu một mã định danh chứa dấu phẩy hoặc dấu ngoặc đơn được nhúng.
Nếu bất cứ ai quan tâm đóng góp một cách tốt hơn để phân tích SQL, điều đó sẽ rất tuyệt!
CẬP NHẬT Tôi tìm thấy một cách tốt hơn để phân tích cú pháp bằng cách sử dụngsqlparse
góinguồn mở. Nếu có bất kỳ sự quan tâm nào tôi sẽ đăng nó ở đây, chỉ cần để lại một bình luận yêu cầu nó ...
import 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
Tôi viết lại câu trả lời @Udinic để mã tự động tạo truy vấn tạo bảng . Nó cũng không cần ConnectionSource
. Nó cũng phải làm điều này trong một giao dịch .
public static String getOneTableDbSchema(SQLiteDatabase db, String tableName) {
Cursor c = db.rawQuery(
"SELECT * FROM `sqlite_master` WHERE `type` = 'table' AND `name` = '" + tableName + "'", null);
String result = null;
if (c.moveToFirst()) {
result = c.getString(c.getColumnIndex("sql"));
}
c.close();
return result;
}
public List<String> getTableColumns(SQLiteDatabase db, String tableName) {
ArrayList<String> columns = new ArrayList<>();
String cmd = "pragma table_info(" + tableName + ");";
Cursor cur = db.rawQuery(cmd, null);
while (cur.moveToNext()) {
columns.add(cur.getString(cur.getColumnIndex("name")));
}
cur.close();
return columns;
}
private void dropColumn(SQLiteDatabase db, String tableName, String[] columnsToRemove) {
db.beginTransaction();
try {
List<String> columnNamesWithoutRemovedOnes = getTableColumns(db, tableName);
// Remove the columns we don't want anymore from the table's list of columns
columnNamesWithoutRemovedOnes.removeAll(Arrays.asList(columnsToRemove));
String newColumnNamesSeparated = TextUtils.join(" , ", columnNamesWithoutRemovedOnes);
String sql = getOneTableDbSchema(db, tableName);
// Extract the SQL query that contains only columns
String oldColumnsSql = sql.substring(sql.indexOf("(")+1, sql.lastIndexOf(")"));
db.execSQL("ALTER TABLE " + tableName + " RENAME TO " + tableName + "_old;");
db.execSQL("CREATE TABLE `" + tableName + "` (" + getSqlWithoutRemovedColumns(oldColumnsSql, columnsToRemove)+ ");");
db.execSQL("INSERT INTO " + tableName + "(" + newColumnNamesSeparated + ") SELECT " + newColumnNamesSeparated + " FROM " + tableName + "_old;");
db.execSQL("DROP TABLE " + tableName + "_old;");
db.setTransactionSuccessful();
} catch {
//Error in between database transaction
} finally {
db.endTransaction();
}
}
DB Browser cho SQLite cho phép bạn thêm hoặc thả các cột.
Trong giao diện chính, tab Database Structure, bấm vào tên bảng. Một nút Modify Tableđược kích hoạt, mở ra một cửa sổ mới nơi bạn có thể chọn cột / trường và loại bỏ nó.
Bạn có thể sử dụng Quản trị viên SQlite để thay đổi tên cột. Nhấp chuột phải vào tên Bảng và chọn Chỉnh sửa Bảng. Ở đây bạn sẽ tìm thấy cấu trúc bảng và bạn có thể dễ dàng đổi tên nó.
Vì SQLite có giới hạn hỗ trợ cho ALTER TABLE, do đó bạn chỉ có thể THÊM cột ở cuối bảng HOẶC THAY ĐỔI TABLE_NAME trong SQLite.
Dưới đây là câu trả lời hay nhất về CÁCH XÓA MÀU SẮC TỪ SQLITE?
truy cập Xóa cột khỏi bảng SQLite
Như một sự thay thế:
Nếu bạn có một bảng với lược đồ
CREATE TABLE person(
id INTEGER PRIMARY KEY,
first_name TEXT,
last_name TEXT,
age INTEGER,
height INTEGER
);
bạn có thể sử dụng một CREATE TABLE...AS
tuyên bố như CREATE TABLE person2 AS SELECT id, first_name, last_name, age FROM person;
, tức là bỏ qua các cột bạn không muốn. Sau đó thả person
bảng gốc và đổi tên bảng mới.
Lưu ý phương pháp này tạo ra một bảng không có KHÓA CHÍNH và không có ràng buộc. Để bảo tồn chúng, hãy sử dụng các phương thức khác được mô tả để tạo bảng mới hoặc sử dụng bảng tạm thời làm trung gian.
Câu trả lời này cho một câu hỏi khác được định hướng để sửa đổi một cột, nhưng tôi tin rằng một phần câu trả lời cũng có thể mang lại một cách tiếp cận hữu ích nếu bạn có nhiều cột và không muốn gõ lại hầu hết chúng cho câu lệnh INSERT của bạn:
https://stackoverflow.com/a/10385666
Bạn có thể kết xuất cơ sở dữ liệu của mình như được mô tả trong liên kết ở trên, sau đó lấy câu lệnh "tạo bảng" và mẫu "chèn" từ kết xuất đó, sau đó làm theo các hướng dẫn trong mục Câu hỏi thường gặp về SQLite "Làm cách nào để thêm hoặc xóa các cột khỏi mục hiện có bảng trong SQLite. " (Câu hỏi thường gặp được liên kết ở nơi khác trên trang này.)
Triển khai Python
dựa trên thông tin tại http://www.sqlite.org/faq.html#q11 .
import sqlite3 as db
import random
import string
QUERY_TEMPLATE_GET_COLUMNS = "PRAGMA table_info(@table_name)"
QUERY_TEMPLATE_DROP_COLUMN = """
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE @tmp_table(@columns_to_keep);
INSERT INTO @tmp_table SELECT @columns_to_keep FROM @table_name;
DROP TABLE @table_name;
CREATE TABLE @table_name(@columns_to_keep);
INSERT INTO @table_name SELECT @columns_to_keep FROM @tmp_table;
DROP TABLE @tmp_table;
COMMIT;
"""
def drop_column(db_file, table_name, column_name):
con = db.connect(db_file)
QUERY_GET_COLUMNS = QUERY_TEMPLATE_GET_COLUMNS.replace("@table_name", table_name)
query_res = con.execute(QUERY_GET_COLUMNS).fetchall()
columns_list_to_keep = [i[1] for i in query_res if i[1] != column_name]
columns_to_keep = ",".join(columns_list_to_keep)
tmp_table = "tmp_%s" % "".join(random.sample(string.ascii_lowercase, 10))
QUERY_DROP_COLUMN = QUERY_TEMPLATE_DROP_COLUMN.replace("@table_name", table_name)\
.replace("@tmp_table", tmp_table).replace("@columns_to_keep", columns_to_keep)
con.executescript(QUERY_DROP_COLUMN)
con.close()
drop_column(DB_FILE, TABLE_NAME, COLUMN_NAME)
Kịch bản này trước tiên tạo bảng tạm thời ngẫu nhiên và chèn dữ liệu của các cột cần thiết ngoại trừ cột sẽ bị loại bỏ. Sau đó khôi phục bảng gốc dựa trên bảng tạm thời và thả bảng tạm thời.
Giải pháp của tôi, chỉ cần gọi phương pháp này.
public static void dropColumn(SQLiteDatabase db, String tableName, String[] columnsToRemove) throws java.sql.SQLException {
List<String> updatedTableColumns = getTableColumns(db, tableName);
updatedTableColumns.removeAll(Arrays.asList(columnsToRemove));
String columnsSeperated = TextUtils.join(",", updatedTableColumns);
db.execSQL("ALTER TABLE " + tableName + " RENAME TO " + tableName + "_old;");
db.execSQL("CREATE TABLE " + tableName + " (" + columnsSeperated + ");");
db.execSQL("INSERT INTO " + tableName + "(" + columnsSeperated + ") SELECT "
+ columnsSeperated + " FROM " + tableName + "_old;");
db.execSQL("DROP TABLE " + tableName + "_old;");
}
Và phương pháp phụ trợ để có được các cột:
public static List<String> getTableColumns(SQLiteDatabase db, String tableName) {
ArrayList<String> columns = new ArrayList<>();
String cmd = "pragma table_info(" + tableName + ");";
Cursor cur = db.rawQuery(cmd, null);
while (cur.moveToNext()) {
columns.add(cur.getString(cur.getColumnIndex("name")));
}
cur.close();
return columns;
}
Tôi đã cải thiện câu trả lời của người dùng2638929 và bây giờ nó có thể bảo tồn loại cột, khóa chính, giá trị mặc định, v.v.
private static void dropColumn(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 + ");");
database.execSQL("INSERT INTO " + tableName + " (" + columnNamesSeparated + ") SELECT "
+ columnNamesSeparated + " FROM " + tableName + "_old;");
database.execSQL("DROP TABLE " + tableName + "_old;");
database.setTransactionSuccessful();
}finally {
database.endTransaction();
}
}
Tái bút Tôi đã sử dụng ở đây android.arch.persistence.db.SupportSQLiteDatabase
, nhưng bạn có thể dễ dàng sửa đổi nó để sử dụngandroid.database.sqlite.SQLiteDatabase
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+";");
}
}
}
}
và chỉ cần gọi một phương thức
DeleteColFromTable("Database name","Table name","Col name which want to delete");
ví dụ để thêm một cột: -
alter table student add column TOB time;
ở đây học sinh là tên_bảng và TOB là cột_name được thêm vào.
Nó đang làm việc và thử nghiệm.
Bây giờ bạn cũng có thể sử dụng trình duyệt DB cho SQLite để thao tác các cột