ฉันต้องการลบหรือเพิ่มคอลัมน์ในฐานข้อมูล 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 คำสั่ง ALTER TABLE ใน SQLite อนุญาตให้ผู้ใช้เปลี่ยนชื่อตารางหรือเพิ่มคอลัมน์ใหม่ในตารางที่มีอยู่ ไม่สามารถเปลี่ยนชื่อคอลัมน์ลบคอลัมน์หรือเพิ่มหรือลบข้อ จำกัด ออกจากตารางได้
คุณสามารถ:
PRAGMA foreign_keys=OFF
ก่อนที่จะทำขั้นตอนนี้และในกรณีที่มีตารางภายนอกหมายถึงหนึ่งตารางต้องสายนี้ ในกรณีนี้หลังจากทำตามลำดับนี้ต้องโทรPRAGMA foreign_keys=ON
เพื่อเปิดใช้งานคีย์ต่างประเทศอีกครั้ง
RENAME COLUMN
ได้รับการสนับสนุน 🎉 sqlite.org/releaselog/3_25_0.html
ฉันได้เขียนการนำ Java ไปใช้ตามวิธีที่แนะนำของ Sqlite ในการทำสิ่งนี้:
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/
INSERT
คำสั่งคุณยังสามารถสร้างตารางใหม่ด้วยการทำ"CREAT TABLE" + tableName + "AS SELECT " + columnsSeperated + " FROM " + tableName + "_old;"
ตามที่คนอื่น ๆ ได้ชี้ให้เห็น
ไม่สามารถเปลี่ยนชื่อคอลัมน์ลบคอลัมน์หรือเพิ่มหรือลบข้อ จำกัด ออกจากตารางได้
แหล่งที่มา: 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
);
CREATE TABLE new_person AS SELECT id, first_name, last_name, age FROM person;
http://www.sqlite.org/lang_altertable.html
อย่างที่คุณเห็นในแผนภาพสนับสนุน ADD COLUMN เท่านั้น มีวิธีแก้ปัญหา (ค่อนข้างหนัก) แต่: http://www.sqlite.org/faq.html#q11
ดังที่คนอื่น ๆ ได้ชี้ให้เห็นALTER TABLE
คำสั่งของ sqlite ไม่สนับสนุนDROP COLUMN
และสูตรมาตรฐานในการทำเช่นนี้ไม่ได้รักษาข้อ จำกัด & ดัชนี
นี่คือบางส่วนของรหัสไพ ธ อนเพื่อทำสิ่งนี้โดยทั่วไปในขณะที่ยังคงรักษาข้อ จำกัด และดัชนีที่สำคัญทั้งหมด
กรุณาสำรองฐานข้อมูลของคุณก่อนที่จะใช้! ฟังก์ชั่นนี้ขึ้นอยู่กับการสร้างคำสั่ง CREATE TABLE ดั้งเดิมและอาจเป็นบิตที่ไม่ปลอดภัย - ตัวอย่างเช่นมันจะทำสิ่งผิดถ้าตัวระบุมีเครื่องหมายจุลภาคหรือเครื่องหมายวงเล็บฝังอยู่
ถ้าใครอยากจะมีส่วนร่วมเป็นวิธีที่ดีกว่าในการแยก SQL ที่จะดี!
อัปเดตฉันพบวิธีที่ดีกว่าในการแยกวิเคราะห์โดยใช้sqlparse
แพ็คเกจโอเพ่นซอร์ส หากมีความสนใจฉันจะโพสต์ได้ที่นี่เพียงแค่แสดงความคิดเห็นขอให้มัน ...
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
ฉันเขียนคำตอบ @Udinicเพื่อให้รหัสสร้างตารางแบบสอบถามการสร้างโดยอัตโนมัติ ConnectionSource
นอกจากนี้ยังไม่จำเป็นต้อง นอกจากนี้ยังมีการทำเช่นนี้ภายในการทำธุรกรรม
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 สำหรับ SQLiteช่วยให้คุณสามารถเพิ่มหรือวางคอลัมน์
ในมุมมองหลักแท็บDatabase Structureคลิกที่ชื่อตาราง ปุ่มModify Tableเปิดใช้งานซึ่งเปิดหน้าต่างใหม่ที่คุณสามารถเลือกคอลัมน์ / ฟิลด์และลบออก
คุณสามารถใช้ Sqlitebrowser ในโหมดเบราว์เซอร์สำหรับฐานข้อมูลที่เกี่ยวข้องและตารางภายใต้โครงสร้างแท็บ - ฐานข้อมูลตามตัวเลือกการปรับเปลี่ยนตารางคอลัมน์ที่เกี่ยวข้องสามารถลบออกได้
ฉันได้ปรับปรุงuser2638929 คำตอบและตอนนี้ก็สามารถรักษาประเภทคอลัมน์คีย์หลักค่าเริ่มต้น ฯลฯ
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();
}
}
PS ฉันใช้ที่นี่android.arch.persistence.db.SupportSQLiteDatabase
แต่คุณสามารถปรับเปลี่ยนได้อย่างง่ายดายเพื่อใช้งานandroid.database.sqlite.SQLiteDatabase
ฉันเดาว่าคุณต้องการทำอะไรนั่นคือการย้ายฐานข้อมูล 'Drop'ping ไม่มีคอลัมน์ใน SQLite แต่อย่างไรก็ตามคุณสามารถเพิ่มคอลัมน์พิเศษได้โดยใช้แบบสอบถามตาราง ALTER
คุณสามารถใช้ผู้ดูแลระบบ SQlite เพื่อเปลี่ยนชื่อคอลัมน์ คลิกขวาที่ชื่อตารางและเลือกแก้ไขตารางที่นี่คุณจะพบโครงสร้างตารางและคุณสามารถเปลี่ยนชื่อได้อย่างง่ายดาย
เนื่องจาก SQLite มีการสนับสนุนที่ จำกัด สำหรับ ALTER TABLE ดังนั้นคุณสามารถเพิ่มได้เฉพาะคอลัมน์ที่ท้ายตารางหรือ CHANGE TABLE_NAME ใน SQLite
นี่คือคำตอบที่ดีที่สุดของวิธีลบคอลัมน์จาก SQLITE
เยี่ยมชมคอลัมน์ลบจากตาราง SQLite
เป็นทางเลือก:
หากคุณมีตารางที่มีสคีมา
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
ตารางต้นฉบับและเปลี่ยนชื่อใหม่
หมายเหตุวิธีนี้สร้างตารางไม่มีคีย์หลักและไม่มีข้อ จำกัด เพื่อรักษาสิ่งเหล่านั้นให้ใช้วิธีการอื่น ๆ ที่อธิบายเพื่อสร้างตารางใหม่หรือใช้ตารางชั่วคราวเป็นสื่อกลาง
คำตอบสำหรับคำถามที่แตกต่างนี้มุ่งเน้นไปที่การปรับเปลี่ยนคอลัมน์ แต่ฉันเชื่อว่าส่วนหนึ่งของคำตอบอาจให้ประโยชน์ที่เป็นประโยชน์หากคุณมีคอลัมน์จำนวนมากและไม่ต้องการพิมพ์อีกครั้งด้วยมือสำหรับคำสั่ง INSERT ของคุณ:
https://stackoverflow.com/a/10385666
คุณสามารถถ่ายโอนฐานข้อมูลของคุณตามที่อธิบายไว้ในลิงค์ด้านบนจากนั้นหยิบคำสั่ง "สร้างตาราง" และเทมเพลต "แทรก" จากการถ่ายโอนข้อมูลนั้นจากนั้นทำตามคำแนะนำในรายการคำถามที่พบบ่อยของ SQLite "ฉันจะเพิ่มหรือลบคอลัมน์จาก ตารางใน SQLite " (คำถามที่พบบ่อยมีการเชื่อมโยงที่อื่นในหน้านี้)
ดำเนินการในPython
บนพื้นฐานของข้อมูลที่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)
สคริปต์นี้สร้างตารางชั่วคราวแบบสุ่มและแทรกข้อมูลของคอลัมน์ที่จำเป็นเท่านั้นยกเว้นคอลัมน์ที่จะถูกทิ้ง จากนั้นคืนค่าตารางดั้งเดิมตามตารางชั่วคราวและวางตารางชั่วคราว
วิธีแก้ปัญหาของฉันจะต้องเรียกวิธีนี้เท่านั้น
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;");
}
และวิธีการเสริมเพื่อรับคอลัมน์:
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;
}
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");
ตอนนี้คุณสามารถใช้เบราว์เซอร์ DB สำหรับ SQLite เพื่อจัดการคอลัมน์
ตัวอย่างการเพิ่มคอลัมน์: -
alter table student add column TOB time;
นักเรียนที่นี่คือtable_nameและTOBคือcolumn_nameที่จะเพิ่ม
มันทำงานและทดสอบ