[sqlite] SQLITE에서 열을 삭제하거나 추가하는 방법은 무엇입니까?

sqlite 데이터베이스에서 열을 삭제하거나 추가하고 싶습니다

다음 쿼리를 사용하여 열을 삭제하고 있습니다.

ALTER TABLE TABLENAME DROP COLUMN COLUMNNAME

그러나 그것은 오류를 준다

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



답변

ALTER TABLE SQLite

SQLite는 ALTER TABLE의 제한된 하위 집합을 지원합니다. SQLite의 ALTER TABLE 명령을 사용하면 테이블 이름을 바꾸거나 기존 테이블에 새 열을 추가 할 수 있습니다. 열 이름을 바꾸거나 열을 제거하거나 테이블에서 제약 조건을 추가하거나 제거 할 수 없습니다.

당신은 할 수 있습니다 :

  1. 변경하려는 테이블로 새 테이블을 만들고
  2. 모든 데이터를 복사
  3. 오래된 테이블을 떨어 뜨리고
  4. 새 이름을 바꿉니다.

답변

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/


답변

다른 사람들이 지적했듯이

열 이름을 바꾸거나 열을 제거하거나 테이블에서 제약 조건을 추가하거나 제거 할 수 없습니다.

출처 : 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
);


답변

http://www.sqlite.org/lang_altertable.html

다이어그램에서 볼 수 있듯이 ADD COLUMN 만 지원됩니다. 그러나 (kinda heavy) 해결 방법이 있습니다 : http://www.sqlite.org/faq.html#q11


답변

SQLite 3에서 특정 열을 삭제할 수 없습니다 . FAQ를 참조하십시오 .


답변

다른 사람들이 지적했듯이, sqlite의 ALTER TABLE진술은 지원 하지 않으며DROP COLUMN , 이것을 수행하는 표준 레시피는 제약 및 지수를 보존하지 않습니다.

다음 모든 주요 제약 조건과 색인 을 유지 하면서 일반적 으로이 작업을 수행하는 Python 코드 입니다.

사용하기 전에 데이터베이스를 백업하십시오! 이 함수는 원래 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();
    }


}