Как проверить в SQLite, существует ли таблица?


895

Как надежно проверить в SQLite, существует ли конкретная пользовательская таблица?

Я не прошу ненадежных способов, таких как проверка, вернул ли «select *» в таблице ошибку или нет (это даже хорошая идея?).

Причина такова:

В моей программе мне нужно создать, а затем заполнить некоторые таблицы, если они еще не существуют.

Если они уже существуют, мне нужно обновить некоторые таблицы.

Должен ли я использовать какой-то другой путь вместо этого, чтобы сигнализировать о том, что соответствующие таблицы уже созданы - например, путем создания / установки / установки определенного флага в файле инициализации / настройки программы на диске или что-то еще?

Или мой подход имеет смысл?


SQLite сгенерирует исключение, если таблица в select не существует. Там просто нет необходимости в более причудливой работе.
NoChance

34
@ Скорее всего, так и будет, но будет и множество других вещей. Это немного похоже на то, чтобы увидеть, действительно ли это дерево, двигаясь вперед с закрытыми глазами, вы узнаете так или иначе :)
randomsock

@randomsock, хороший пример, но немного страшно, особенно, если машина была моей машиной ...
NoChance

@randomsock, я не знаю, что такое соглашение по sqlite, но просить прощения более питонно, чем разрешение. т.е. ловить исключение вместо использования условного.
Эрик

1
@Eric На данный момент этот вопрос не касается Python, но при условии, что это так, ошибка является общей sqlite3.OperationalError, поэтому вам нужно проанализировать сообщение об ошибке, чтобы убедиться, что это, например, сообщение «таблица TABLE_NAME уже существует» при создании таблица, а если нет, то переформулируйте ошибку, и я думаю, что нет никакой гарантии, что формулировка ошибки не изменится.
Маркус фон

Ответы:


1023

Я пропустил эту запись FAQ.

В любом случае, для дальнейшего использования, полный запрос:

SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}';

Где {table_name}имя таблицы для проверки.

Раздел документации для справки: Формат файла базы данных. 2.6. Хранение схемы базы данных SQL

  • Это вернет список таблиц с указанным именем; то есть курсор будет иметь счетчик 0 (не существует) или счетчик 1 (существует)

7
Какая из документов SQLite охватывает эти системные таблицы?
Павел Веселов

29
@ Павел Веселов: Раздел под названием «Формат файла для баз данных SQLite»: sqlite.org/fileformat2.html
Брайан Оукли

14
Это не будет работать для таблиц TEMP, однако. Таблицы TEMP находятся в «sqlite_temp_master».
PatchyFog

11
Это возвращает логическое значение? Что он возвращает, если таблица существует или не существует?
Dagrooms

8
@Dagrooms Возвращает список таблиц с указанным именем; то есть курсор будет иметь счет 0 (не существует) или 1 (существует).
Рейн С

555

Если вы используете SQLite версии 3.3+, вы можете легко создать таблицу с:

create table if not exists TableName (col1 typ1, ..., colN typN)

Таким же образом вы можете удалить таблицу, только если она существует, используя:

drop table if exists TableName

3
Обратите внимание, что create tableоператор является неполным (отсутствует спецификация столбцов таблицы).
Эрик Платон

11
Существует также аналогичная конструкция для индексов: создайте индекс, если он не существует. TableName_col1 для TableName (col1)
lowtech

26
Это не должен быть принятый ответ, но был бы, если бы вопрос был сформулирован по-другому. ОП не спрашивал, как проверить таблицу перед тем, как уронить или создать. Что делать, если вам нужно запросить таблицу, которая, возможно, не существует? Это проблема, с которой я сталкиваюсь сейчас, и принятый ответ лучше всего работает в этой общей формулировке проблемы. Это хорошая быстрая альтернатива.
Dagrooms

@ Dagrooms, ты можешь быть прав. Хотя ОП не спрашивал об этом, я искал этот ответ :)
earik87

169

Вариантом будет использование SELECT COUNT (*) вместо SELECT NAME, т.е.

SELECT count(*) FROM sqlite_master WHERE type='table' AND name='table_name';

Это вернет 0, если таблица не существует, 1, если она существует. Это, вероятно, полезно в вашем программировании, поскольку численный результат обрабатывается быстрее / проще. Ниже показано, как вы можете сделать это в Android, используя SQLiteDatabase, Cursor, rawQuery с параметрами.

boolean tableExists(SQLiteDatabase db, String tableName)
{
    if (tableName == null || db == null || !db.isOpen())
    {
        return false;
    }
    Cursor cursor = db.rawQuery("SELECT COUNT(*) FROM sqlite_master WHERE type = ? AND name = ?", new String[] {"table", tableName});
    if (!cursor.moveToFirst())
    {
        cursor.close();
        return false;
    }
    int count = cursor.getInt(0);
    cursor.close();
    return count > 0;
}

33
Я верю, что «ВЫБОР 1» будет еще быстрее.
PatchyFog

Почему cursor.getInt (0) равно количеству записей в базе данных?
Семен Данилов

1
Мы рассчитываем, сколько раз TABLE появляется в схеме sqlite. Число 0 означает, что таблица не существует. Число 1 означает, что таблица существует. Это единственные два ожидаемых значения количества.
Стивен Куан

1
Хотя число (из COUNT(*)) легко обрабатывается, еще проще вернуть существование строки или нет; если там есть строка, то она существует, если нет строки, то ее нет. (Вы уже проверите на провал в moveToFirst, так что работа будет выполнена в этот момент.)
dash-tom-bang

Пожалуйста, обновите ваш код, чтобы закрыть курсор, прежде чем вы вернете false.
Дейв Томас

43

Вы можете попробовать:

SELECT name FROM sqlite_master WHERE name='table_name'

4
type = table было бы полезно tho
mafu

Если используется C #, не используйте эту команду в a SQLiteReader reader = cmd.ExecuteReader();и выполните a dt.Load(reader)(где dtis DataTable). Я обнаружил, что это Object reference is not an instance of an objectисключение, .Load()если таблица не найдена. Вместо этого используйте SQLiteDataAdapter adapter = new SQLiteDataAdapter(cmd); и делайте adapter.Fill(ds), где dsесть DataSet. Затем вы можете увидеть, если ds.Tables.Count > 0и return ds.Tables[0];если да (или else return null). Тогда вы можете проверить это DataTableдля того null, чтобы быть , если dt.Rows != nullи еслиdt.Rows.Count>0
vapcguy

35

Использование:

PRAGMA table_info(your_table_name)

Если полученная таблица пуста, то your_table_nameне существует.

Документация:

PRAGMA schema.table_info (имя таблицы);

Эта прагма возвращает одну строку для каждого столбца в именованной таблице. Столбцы в наборе результатов включают имя столбца, тип данных, может ли столбец иметь значение NULL и значение по умолчанию для столбца. Столбец «pk» в наборе результатов равен нулю для столбцов, которые не являются частью первичного ключа, и является индексом столбца в первичном ключе для столбцов, которые являются частью первичного ключа.

Таблица, названная в прагме table_info, также может быть представлением.

Пример вывода:

cid|name|type|notnull|dflt_value|pk
0|id|INTEGER|0||1
1|json|JSON|0||0
2|name|TEXT|0||0

Это отличный способ определить, существует ли таблица в Python.
Майкл Мерфи

или формы Xamarin
SerenityNow

4
Это отличный способ получить определения столбцов программно
w00t

33

Имена таблиц SQLite нечувствительны к регистру, но сравнение по умолчанию чувствительно к регистру. Чтобы это работало правильно, во всех случаях нужно добавить COLLATE NOCASE.

SELECT name FROM sqlite_master WHERE type='table' AND name='table_name' COLLATE NOCASE

33

Если вы получаете сообщение об ошибке «таблица уже существует», внесите изменения в строку SQL, как показано ниже:

CREATE table IF NOT EXISTS table_name (para1,para2);

Таким образом, вы можете избежать исключений.



23

Если вы используете fmdb , я думаю, вы можете просто импортировать FMDatabaseAdditions и использовать функцию bool:

[yourfmdbDatabase tableExists:tableName].

1
Убедитесь, что вы импортировали «FMDatabaseAdditions.h», чтобы использовать этот метод, иначе вам будет интересно, почему они его удалили! :)
Will

Хотя это может быть правильным ответом, вопрос был о sqlite, а не о конкретной библиотеке на определенном языке. Я думаю, что ответом должно быть предоставление кода SQL, а не вызов одного из методов библиотеки
nacho4d

13

Следующий код возвращает 1, если таблица существует, или 0, если таблица не существует.

SELECT CASE WHEN tbl_name = "name" THEN 1 ELSE 0 END FROM sqlite_master WHERE tbl_name = "name" AND type = "table"

1
Это все равно ничего не вернет, если таблица не существует, потому что условие where предотвращает любой результат.
Дэвид Гаусманн

10

Обратите внимание, что для проверки существования таблицы в базе данных TEMP вы должны использовать sqlite_temp_masterвместо sqlite_master:

SELECT name FROM sqlite_temp_master WHERE type='table' AND name='table_name';

9

Вот функция, которую я использовал:

Имеется объект SQLDatabase = db

public boolean exists(String table) {
    try {
         db.query("SELECT * FROM " + table);
         return true;
    } catch (SQLException e) {
         return false;
    }
}

1
К сожалению, мне пришлось использовать это в моем приложении для Android, так как я обнаружил, что устройства Samsung не используют стандартную структуру таблицы sqlite_master, с которой все остальные работают.
Энтони Чуинард

7

Используйте этот код:

SELECT name FROM sqlite_master WHERE type='table' AND name='yourTableName';

Если количество возвращаемых массивов равно 1, это означает, что таблица существует. В противном случае его не существует.


4
class CPhoenixDatabase():
    def __init__(self, dbname):
        self.dbname = dbname
        self.conn = sqlite3.connect(dbname)

    def is_table(self, table_name):
        """ This method seems to be working now"""
        query = "SELECT name from sqlite_master WHERE type='table' AND name='{" + table_name + "}';"
        cursor = self.conn.execute(query)
        result = cursor.fetchone()
        if result == None:
            return False
        else:
            return True

Примечание: теперь это работает на моем Mac с Python 3.7.1


Это выглядит чище, чем все остальные ответы .. Спасибо!
Харша

Не работает для меня: нужно удалить квадратные скобки {} вокруг table_name, тогда это нормально.
банан

1
Убедитесь, что table_nameон не предоставляется из ненадежного источника (например, пользовательского ввода), иначе он будет уязвим для внедрения SQL. Всегда лучше использовать параметры вместо методов обработки текста
astef

3

использование

SELECT 1 FROM table LIMIT 1;

чтобы предотвратить чтение всех записей.


Это возвращает NULL, если таблица существует, но не имеет никаких записей.
радиоспил

Если таблица не существует, она выдаст ошибку. Поймай это, и ты знаешь, что этого не существует.
luckydonald

использование обработки ошибок в качестве управления потоком обычно не считается наилучшей практикой. Этого, вероятно, следует избегать.
Джефф Вудард

3

Вы можете написать следующий запрос для проверки существования таблицы.

SELECT name FROM sqlite_master WHERE name='table_name'

Здесь 'table_name' - это имя вашей таблицы, которое вы создали. Например

 CREATE TABLE IF NOT EXISTS country(country_id INTEGER PRIMARY KEY AUTOINCREMENT, country_code TEXT, country_name TEXT)"

и проверить

  SELECT name FROM sqlite_master WHERE name='country'

6
Чем это отличается от уже принятого топ-9 ответа назад?
Кевин Ван Дейк,

3

Самый надежный способ, который я нашел в C # прямо сейчас, с использованием новейшего пакета sqlite-net-pcl nuget (1.5.231), использующего SQLite 3, заключается в следующем:

var result = database.GetTableInfo(tableName);
if ((result == null) || (result.Count == 0))
{
    database.CreateTable<T>(CreateFlags.AllImplicit);
}

2

Использование простого запроса SELECT, на мой взгляд, довольно надежно. Больше всего он может проверять существование таблицы во многих различных типах баз данных (SQLite / MySQL).

SELECT 1 FROM table;

Это имеет смысл, когда вы можете использовать другой надежный механизм определения успешности запроса (например, вы запрашиваете базу данных через QSqlQuery в Qt ).


1

Функция c ++ проверяет БД и все подключенные базы данных на наличие таблицы и (необязательно) столбца.

bool exists(sqlite3 *db, string tbl, string col="1")
{
    sqlite3_stmt *stmt;
    bool b = sqlite3_prepare_v2(db, ("select "+col+" from "+tbl).c_str(),
    -1, &stmt, 0) == SQLITE_OK;
    sqlite3_finalize(stmt);
    return b;
}

Изменить: Недавно обнаружил функцию sqlite3_table_column_metadata. следовательно

bool exists(sqlite3* db,const char *tbl,const char *col=0)
{return sqlite3_table_column_metadata(db,0,tbl,col,0,0,0,0,0)==SQLITE_OK;}

public static логическое tableExists (база данных SQLiteDatabase, String tableName) {return database.rawQuery ("ВЫБЕРИТЕ имя ИЗ sqlite_master WHERE type = 'table' AND name = '" + tableName + "'", null) .moveToFirst (); }
ник

Очень неэффективный и рискованный способ, так как конкатенация строк может привести ко всему.
Андреа Моро

0

Это мой код для SQLite Cordova:

get_columnNames('LastUpdate', function (data) {
    if (data.length > 0) { // In data you also have columnNames
        console.log("Table full");
    }
    else {
        console.log("Table empty");
    }
});

И другой:

function get_columnNames(tableName, callback) {
    myDb.transaction(function (transaction) {
        var query_exec = "SELECT name, sql FROM sqlite_master WHERE type='table' AND name ='" + tableName + "'";
        transaction.executeSql(query_exec, [], function (tx, results) {
            var columnNames = [];
            var len = results.rows.length;
            if (len>0){
                var columnParts = results.rows.item(0).sql.replace(/^[^\(]+\(([^\)]+)\)/g, '$1').split(','); ///// RegEx
                for (i in columnParts) {
                    if (typeof columnParts[i] === 'string')
                        columnNames.push(columnParts[i].split(" ")[0]);
                };
                callback(columnNames);
            }
            else callback(columnNames);
        });
    });
}

0

Я думал, что я бы положил свои 2 цента на это обсуждение, даже если оно довольно старое. Этот запрос возвращает скалярное значение 1, если таблица существует, и 0 в противном случае.

select 
    case when exists 
        (select 1 from sqlite_master WHERE type='table' and name = 'your_table') 
        then 1 
        else 0 
    end as TableExists

0

Таблица существует или нет в базе данных в Swift

func tableExists(_ tableName:String) -> Bool {
        sqlStatement = "SELECT name FROM sqlite_master WHERE type='table' AND name='\(tableName)'"
        if sqlite3_prepare_v2(database, sqlStatement,-1, &compiledStatement, nil) == SQLITE_OK {
            if sqlite3_step(compiledStatement) == SQLITE_ROW {
                return true
            }
            else {
                return false
            }
        }
        else {
            return false
        }
            sqlite3_finalize(compiledStatement)
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.