[sqlite] SQLite에없는 경우 ALTER TABLE ADD COLUMN

최근에 기존 SQLite 데이터베이스 테이블 몇 개에 열을 추가해야했습니다. 이것은 ALTER TABLE ADD COLUMN. 물론 테이블이 이미 변경된 경우에는 그대로 두어야합니다. 불행하게도, SQLite는은 지원하지 않습니다 IF NOT EXISTS에 절을 ALTER TABLE.

현재 해결 방법은 이 Python 예제 와 마찬가지로 ALTER TABLE 문을 실행하고 “중복 된 열 이름”오류를 무시하는 것입니다 (그러나 C ++에서).

그러나 데이터베이스 스키마를 설정하는 일반적인 접근 방식은 또는 명령 줄 도구를 사용하여 실행할 수있는 CREATE TABLE IF NOT EXISTSCREATE INDEX IF NOT EXISTS문을 포함하는 .sql 스크립트를 사용 sqlite3_exec하는 것 sqlite3입니다. ALTER TABLE이 스크립트 파일을 넣을 수 없습니다. 그 문이 실패하면 그 이후의 어떤 것도 실행되지 않기 때문입니다.

테이블 정의를 한곳에두고 .sql과 .cpp 파일로 나누지 않고 싶습니다. ALTER TABLE ADD COLUMN IF NOT EXISTS순수한 SQLite SQL에서 해결 방법을 작성하는 방법이 있습니까?



답변

99 % 순수한 SQL 방법이 있습니다. 아이디어는 스키마를 버전 화하는 것입니다. 두 가지 방법으로이 작업을 수행 할 수 있습니다.

  • ‘user_version’pragma 명령 ( PRAGMA user_version)을 사용하여 데이터베이스 스키마 버전에 대한 증분 번호를 저장합니다.

  • 고유 한 정의 된 테이블에 버전 번호를 저장하십시오.

이러한 방식으로 소프트웨어가 시작되면 데이터베이스 스키마를 확인하고 필요한 경우 ALTER TABLE쿼리를 실행 한 다음 저장된 버전을 증가시킬 수 있습니다. 특히 데이터베이스가 수년에 걸쳐 몇 번 증가하고 변경되는 경우 다양한 업데이트를 “블라인드”하는 것보다 훨씬 낫습니다.


답변

한 가지 해결 방법은 열을 생성하고 열이 이미 존재하는 경우 발생하는 예외 / 오류를 포착하는 것입니다. 여러 열을 추가 할 때 하나의 중복으로 인해 다른 열이 생성되는 것을 막지 않도록 별도의 ALTER TABLE 문에 추가합니다.

sqlite가-NET , 우리는 다음과 같이했다. 중복 된 sqlite 오류를 다른 sqlite 오류와 구별 할 수 없기 때문에 완벽하지 않습니다.

Dictionary<string, string> columnNameToAddColumnSql = new Dictionary<string, string>
{
    {
        "Column1",
        "ALTER TABLE MyTable ADD COLUMN Column1 INTEGER"
    },
    {
        "Column2",
        "ALTER TABLE MyTable ADD COLUMN Column2 TEXT"
    }
};

foreach (var pair in columnNameToAddColumnSql)
{
    string columnName = pair.Key;
    string sql = pair.Value;

    try
    {
        this.DB.ExecuteNonQuery(sql);
    }
    catch (System.Data.SQLite.SQLiteException e)
    {
        _log.Warn(e, string.Format("Failed to create column [{0}]. Most likely it already exists, which is fine.", columnName));
    }
}


답변

SQLite는 또한 “table_info”라는 pragma 문을 지원합니다.이 구문은 열 이름 (및 열에 대한 기타 정보)이있는 테이블의 열당 한 행을 반환합니다. 쿼리에서 이것을 사용하여 누락 된 열을 확인하고 존재하지 않는 경우 테이블을 변경할 수 있습니다.

PRAGMA table_info(foo_table_name)

http://www.sqlite.org/pragma.html#pragma_table_info


답변

DB 업그레이드 문에서이 작업을 수행하는 경우 가장 간단한 방법은 이미 존재할 수있는 필드를 추가하려고 할 때 throw되는 예외를 포착하는 것입니다.

try {
   db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN foo TEXT default null");
} catch (SQLiteException ex) {
   Log.w(TAG, "Altering " + TABLE_NAME + ": " + ex.getMessage());
}


답변

threre는 PRAGMA의 방법으로 table_info (table_name)이며 테이블의 모든 정보를 반환합니다.

다음은 체크 컬럼 존재 여부에 대한 구현 방법입니다.

    public boolean isColumnExists (String table, String column) {
         boolean isExists = false
         Cursor cursor;
         try {
            cursor = db.rawQuery("PRAGMA table_info("+ table +")", null);
            if (cursor != null) {
                while (cursor.moveToNext()) {
                    String name = cursor.getString(cursor.getColumnIndex("name"));
                    if (column.equalsIgnoreCase(name)) {
                        isExists = true;
                        break;
                    }
                }
            }

         } finally {
            if (cursor != null && !cursor.isClose())
               cursor.close();
         }
         return isExists;
    }

루프를 사용하지 않고이 쿼리를 사용할 수도 있습니다.

cursor = db.rawQuery("PRAGMA table_info("+ table +") where name = " + column, null);


답변

pragma table_info()더 큰 SQL의 일부로의 결과 를 사용하려는 경우 .

select count(*) from
pragma_table_info('<table_name>')
where name='<column_name>';

핵심 부분은 사용하는 것 pragma_table_info('<table_name>')대신에 pragma table_info('<table_name>').


이 답변은 @Robert Hawkey의 답변에서 영감을 받았습니다. 내가 새 답변으로 게시하는 이유는 댓글로 게시 할 평판이 충분하지 않기 때문입니다.


답변

이 쿼리를 생각해 냈습니다.

SELECT CASE (SELECT count(*) FROM pragma_table_info(''product'') c WHERE c.name = ''purchaseCopy'') WHEN 0 THEN ALTER TABLE product ADD purchaseCopy BLOB END
  • 내부 쿼리는 열이있는 경우 0 또는 1을 반환합니다.
  • 결과에 따라 열을 변경하십시오.