본문 바로가기
프로그래밍

안드로이드 DB 컬럼 추가 (Upgrade) 방법

by hansoo.labs 한수댁 2020. 4. 2.

How to upgrade database version with adding new columns in android?

안드로이드 데이터베이스 (SQLite)를 이미 생성한 이후에 테이블에 컬럼을 추가하고자 할 때 참고.

아래와 같이 버전 1의 테이블 생성 내용이다. 여기에 컬럼하나를 끝에 추가하려고 한다.

private static final String _ID = "idx";
private static final String KEY_ID = "_id";
private static final String KEY_TITLE = "title";
private static final String KEY_DESC = "desc";
private static final String KEY_BUDGET = "budget";
private static final String KEY_BUDGET_USE = "budgetuse";
private static final String KEY_CREATE_TIME = "recordtime";
private static final String KEY_HIDDEN = "hidden";
private static final String KEY_MODE = "mode";
private static final String KEY_TOTAL = "total";
private static final String KEY_COUNT = "count";
private static final String KEY_ORDERING = "ordering";

private static final String DATABASE_CREATE = 
        "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + 
        " (" + 
        _ID                    + " Integer PRIMARY KEY AUTOINCREMENT, " +
        KEY_ID                + " Long DEFAULT 0," +
        KEY_TITLE                + " Text NOT NULL," +
        KEY_DESC                + " Text NOT NULL," +
        KEY_BUDGET            + " Real DEFAULT 0," +
        KEY_BUDGET_USE        + " Integer DEFAULT 0," +
        KEY_CREATE_TIME        + " Long DEFAULT 0," +
        KEY_HIDDEN            + " Integer DEFAULT 0," +
        KEY_MODE            + " Integer DEFAULT 0," +
        KEY_TOTAL             + " Real DEFAULT 0," +
        KEY_COUNT             + " Integer DEFAULT 0," +
        KEY_ORDERING            + " Integer DEFAULT 0" +
        ");";

위에 버전 1의 생성코드에 컬럼을 하나 추가한다.

//ver 2
private static final String KEY_IMPORTANT = "important";

private static final String DATABASE_CREATE = 
        "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + 
        " (" + 
        _ID                    + " Integer PRIMARY KEY AUTOINCREMENT, " +
        KEY_ID                + " Long DEFAULT 0," +
        KEY_TITLE                + " Text NOT NULL," +
        KEY_DESC                + " Text NOT NULL," +
        KEY_BUDGET            + " Real DEFAULT 0," +
        KEY_BUDGET_USE        + " Integer DEFAULT 0," +
        KEY_CREATE_TIME        + " Long DEFAULT 0," +
        KEY_HIDDEN            + " Integer DEFAULT 0," +
        KEY_MODE            + " Integer DEFAULT 0," +
        KEY_TOTAL             + " Real DEFAULT 0," +
        KEY_COUNT             + " Integer DEFAULT 0," +
        KEY_ORDERING            + " Integer DEFAULT 0," +
        KEY_IMPORTANT        + " Integer DEFAULT 0" + //added in ver 2
        ");";

그 다음 SQLiteOpenHelper 확장 클래스의 onUpgrade 함수를 이렇게 수정.

private static class DatabaseOpenHelper extends SQLiteOpenHelper {

    private static final String TAG = MyConfig.TAG;
    private static final String NAME = "DatabaseOpenHelper";
    private final String CLASS = NAME + "@" + Integer.toHexString(hashCode());


    DatabaseOpenHelper(Context context, String name,
            CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    public void onCreate(SQLiteDatabase db) {
        db.execSQL(DATABASE_CREATE);

    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        HLog.w(TAG, CLASS, "Upgrading from version " + oldVersion
                + " to " + newVersion);

        if (oldVersion < 2) { // case 1
            try {
                db.beginTransaction();
                db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + KEY_IMPORTANT + " Integer DEFAULT 0");
                db.setTransactionSuccessful();
            } catch (IllegalStateException e) {
                HLog.e(TAG, CLASS, e);
            } finally {
                db.endTransaction();
            }
        }
    }
}

위 코드에서 super(context, name, factory, version) 함수의 version 값이 올라가면 onUpgrade 함수가 호출된다. 이전 버전이 1일 때만 테이블 변경을 시도하도록 했다. DB 생성 코드에 추가된 컬럼을 적었기 때문에 버전 2 이상으로 처음 설치하는 사람들은 DB Upgrade를 할 필요가 없다. 주의할 점은 이전 버전을 if 문으로 비교하길 추천한다. 이후 계속적으로 버전이 올라갈 경우 이전 버전들을 지원하기 위해서는 모든 버전업에 대한 처리가 필요하기 때문이다.

버전업을 하면서 테이블도 추가하고 추가된 테이블에 컬럼도 수정해야 했던 실제 저의 코드를 예를 들어본다.

private class ListDBCallback(version: Int, private val openComplete: Command?)
    : SupportSQLiteOpenHelper.Callback(version) {
    private val klass = "ListDB.DBCallback@" + Integer.toHexString(hashCode())

    override fun onOpen(db: SupportSQLiteDatabase) {
        super.onOpen(db)
        openComplete?.invoke()
    }

    override fun onCreate(db: SupportSQLiteDatabase) {
        db.execSQL(TableList.CREATE_SQL)
        db.execSQL(TableTag.CREATE_SQL)
        db.execSQL(TableListTag.CREATE_SQL)
    }

    override fun onUpgrade(db: SupportSQLiteDatabase, oldVersion: Int, newVersion: Int) {
        HLog.i(klass, "onUpgrade", "from version $oldVersion to $newVersion")
        try {
            db.beginTransaction()

            if (oldVersion < 2) {
                db.execSQL("ALTER TABLE ${TableList.TABLE} ADD COLUMN ${TableList.KEY_IMPORTANT} Integer DEFAULT 0")
            }
            if (oldVersion < 5) {
                db.execSQL("Alter Table ${TableList.TABLE} Add Column ${TableList.KEY_SAMPLE} Integer Default 0")
            }
            if (oldVersion < 6) {
                db.execSQL("Alter Table ${TableList.TABLE} Add Column ${TableList.KEY_CURRENCY_CODE} Text ")
            }
            if (oldVersion < 7) {
                db.execSQL("Alter Table ${TableList.TABLE} Add Column ${TableList.KEY_VERSION} Integer Default 1")
            }
            if (oldVersion < 8) {
                db.execSQL("Alter Table ${TableList.TABLE} Add Column ${TableList.KEY_ARCHIVED_AT} Long Default 0")
            }
            if (oldVersion < 10) {
                db.execSQL("Alter Table ${TableList.TABLE} Add Column ${TableList.KEY_DROP_MODE} Integer Default 0")
            }
            var addedTagTables = false
            if (oldVersion < 13) {
                db.execSQL(TableTag.CREATE_SQL)
                db.execSQL(TableListTag.CREATE_SQL)
                addedTagTables = true
            }
            if (oldVersion < 14 && !addedTagTables) { // 13버전에서 테이블을 추가했다면 제외.
                db.execSQL("Alter Table ${TableTag.TABLE} Add Column ${TableTag.KEY_ORDERING} Text Default ${Ordering.UpdateTime.name}")
                db.execSQL("Alter Table ${TableListTag.TABLE} Add Column ${TableListTag.KEY_ORD} Integer Default 0")
            }
            if (oldVersion < 15) {
                db.execSQL("Alter Table ${TableList.TABLE} Add Column ${TableList.KEY_LOCKED} Integer Default 0")
            }
            db.setTransactionSuccessful()

        } catch (e: IllegalStateException) {
            HLog.e(klass, "onUpgrade", e)
            Crashlytics.logException(e)
        } finally {
            db.endTransaction()
        }
    }
}

댓글5

  • Favicon of https://birdstrike.tistory.com BlogIcon 만델라 2017.02.02 14:28 신고

    님 감사합니다.
    제가 이미 출시된 앱에서 업데이트 하면서 테이블의 열을 추가시키는 공부를 하고 있습니다.
    확인차 질문 한번 드립니다.
    DatabaseOpenHelper의 객체 dbHelper라는걸 만들어주고
    dbHelper.onUpgrade(db, 1, 2);
    당연히 이런식으로 onUpgrade()를 호출을 해야 db가 2버전으로 업그레이드되는거겠쬬???
    그냥 소스내에 dbVersion = 2; 라고 적어둔다고 자동으로 호출되지 않겠죠?
    onCreate()는 최초에 db가 없을 때 자동 호출되는것 같더라구요. 그이후론 db가 있으니 생성이 안되구요.
    onUpgrade()도 혹시 그런가???했는데 안그러네요.ㅎ
    위에 제가 궁금해 하는게 맞나요???
    답글

  • onUpgrade는 자동으로 호출되요. 헬퍼 인스턴스를 만들 때 버전 정보를 넣어주기 때문에 동작하게 되요.
    답글

  • yyyy 2020.07.06 16:44

    안녕하세요 혹시 저렇게 하면 버전 1에서 이미 저장되어진 데이터들은 그대로 갖고있는채로 버전2에서 컬럼이 추가되고 데이터도 보존한채로 인가요?
    아니면 버전2로 올리면 그냥 기존 데이터는 삭제되고 새로 데이터들을 집어넣어야하나요?
    답글