ALTER TABLE ADD COLUMN ЕСЛИ НЕ СУЩЕСТВУЕТ в SQLite

71

Недавно нам потребовалось добавить столбцы в некоторые из существующих таблиц базы данных SQLite. Это можно сделать с помощью ALTER TABLE ADD COLUMN. Конечно, если таблица уже была изменена, мы хотим оставить ее в покое. К сожалению, SQLite не поддерживает предложение IF NOT EXISTS на ALTER TABLE.

Нашим текущим решением является выполнение инструкции ALTER TABLE и игнорирование любых ошибок "дублированного столбца", как этот пример Python (но на С++).

Однако наш обычный подход к настройке схем баз данных состоит в том, чтобы иметь .sql script, содержащий операторы CREATE TABLE IF NOT EXISTS и CREATE INDEX IF NOT EXISTS, которые могут быть выполнены с помощью sqlite3_exec или инструмента командной строки sqlite3. Мы не можем помещать ALTER TABLE в эти файлы script, потому что, если этот оператор терпит неудачу, ничего после его выполнения не будет.

Я хочу иметь определения таблиц в одном месте и не разбивать файлы .sql и .cpp. Есть ли способ написать обходной путь для ALTER TABLE ADD COLUMN IF NOT EXISTS в чистом SQLite SQL?

Теги:
alter-table

6 ответов

51

У меня есть метод 99% чистого SQL. Идея состоит в том, чтобы создать версию вашей схемы. Вы можете сделать это двумя способами:

  • Используйте команду прагмы 'user_version' ( PRAGMA user_version), чтобы сохранить добавочный номер для вашей версии схемы базы данных.

  • Сохраните ваш номер версии в вашей собственной определенной таблице.

Таким образом, когда программное обеспечение запущено, оно может проверить схему базы данных и, если необходимо, выполнить запрос ALTER TABLE, а затем увеличить сохраненную версию. Это гораздо лучше, чем пытаться делать всевозможные "слепые" обновления, особенно если ваша база данных растет и изменяется несколько раз за последние годы.

  • 0
    +1 за версионность вашей схемы с использованием PRAGMA user_version. Очень просто и удобно, так как вам не нужно вести другой стол.
  • 6
    Каково начальное значение user_version ? Я предполагаю ноль, но было бы неплохо увидеть это документально.
Показать ещё 8 комментариев
24

Один способ - просто создать столбцы и уловить исключение/ошибку, возникающие, если столбец уже существует. При добавлении нескольких столбцов добавьте их в отдельные инструкции 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));
    }
}
  • 7
    Если вы проголосовали, пожалуйста, прокомментируйте почему.
  • 0
    Круто, это то, что мне нужно!
Показать ещё 4 комментария
23

SQLite также поддерживает инструкцию pragma, называемую "table_info", которая возвращает одну строку за столбец в таблице с именем столбца (и другой информацией о столбце). Вы можете использовать это в запросе для проверки отсутствующего столбца, а если нет, измените таблицу.

PRAGMA table_info(foo_table_name)

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

  • 19
    Ваш ответ был бы намного лучше, если бы вы предоставили код для завершения поиска, а не просто ссылку.
  • 0
    PRAGMA table_info (имя_таблицы). Эта команда перечислит каждый столбец table_name как строку в результате. На основании этого результата вы можете определить, существует столбец или нет.
Показать ещё 5 комментариев
13

Если вы делаете это в инструкции обновления БД, возможно, самый простой способ - просто уловить исключение, возникшее, если вы пытаетесь добавить поле, которое может уже существовать.

try {
   db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN foo TEXT default null");
} catch (SQLiteException ex) {
   Log.w(TAG, "Altering " + TABLE_NAME + ": " + ex.getMessage());
}
  • 0
    Я не люблю программирование в стиле исключений, но это удивительно чисто. Может быть, вы меня немного покачали.
  • 0
    Мне это тоже не нравится, но C ++ - самый распространенный язык программирования в стиле исключений. Так что я думаю, что все еще можно увидеть это как "действительный".
Показать ещё 1 комментарий
10

есть метод 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);
  • 0
    Cursor cursor = db.rawQuery ("выберите * из таблицы имен", ноль); columns = cursor.getColumnNames ();
  • 1
    Я думаю, вы забыли закрыть курсор :-)
Показать ещё 1 комментарий
0

Если у вас возникла эта проблема в flex/adobe air и сначала найдите его, я нашел решение и разместил его по соответствующему вопросу: ADD COLUMN to sqlite db ЕСЛИ НЕ СУЩЕСТВУЕТ - flex/air sqlite?

Мой комментарий здесь: https://stackoverflow.com/questions/2614728/add-column-to-sqlite-db-if-not-exists-flex-air-sqlite

Ещё вопросы

Сообщество Overcoder
Наверх
Меню