Jak sprawdzić w SQLite, czy tabela istnieje?

893

Jak niezawodnie sprawdzać w SQLite, czy istnieje konkretna tabela użytkowników?

Nie pytam o niewiarygodne sposoby, takie jak sprawdzenie, czy „select *” na stole zwróciło błąd, czy nie (czy to nawet dobry pomysł?).

Powód jest następujący:

W moim programie muszę utworzyć, a następnie wypełnić niektóre tabele, jeśli jeszcze nie istnieją.

Jeśli już istnieją, muszę zaktualizować niektóre tabele.

Czy zamiast tego powinienem wybrać inną ścieżkę, aby zasygnalizować, że tabele, o których mowa, zostały już utworzone - powiedzmy na przykład, tworząc / umieszczając / ustawiając określoną flagę w pliku inicjalizacji / ustawień mojego programu na dysku lub coś takiego?

Czy moje podejście ma sens?

PoorLuzer
źródło
SQLite zgłosi wyjątek, jeśli tabela w zaznaczeniu nie istnieje. Po prostu nie ma już potrzeby wymyślnej pracy.
NoChance,
34
@NoChance to zrobi, ale będzie też wiele innych rzeczy. To trochę jak sprawdzenie, czy to drzewo naprawdę tam jest, jeżdżąc do przodu z zamkniętymi oczami, dowiesz się w ten czy inny sposób :)
randomsock
@randomsock, fajny przykład, ale trochę przerażający, szczególnie jeśli samochód
byłby
@ randomsock, nie wiem, jaka jest konwencja sqlite, ale bardziej pytoniczne jest proszenie o wybaczenie niż o pozwolenie. tzn. złap wyjątek zamiast używać warunkowego.
Eric
1
@Eric Na razie pytanie nie dotyczy Pythona, ale zakładając, że tak, błąd jest ogólny sqlite3.OperationalError, więc musisz przeanalizować komunikat o błędzie, aby upewnić się, że np. Komunikat „Tabela TABLE_NAME już istnieje” podczas tworzenia tabeli, a jeśli nie, popraw błąd i myślę, że nie ma gwarancji, że sformułowanie błędu się nie zmieni.
Markus von Broady,

Odpowiedzi:

1020

Brakowało mi tego wpisu FAQ.

W każdym razie, do wglądu w przyszłości, pełne zapytanie to:

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

Gdzie {table_name}jest nazwa tabeli do sprawdzenia.

Dokumentacja w celach informacyjnych: Format pliku bazy danych. 2.6 Przechowywanie schematu bazy danych SQL

  • Spowoduje to zwrócenie listy tabel o podanej nazwie; to znaczy kursor będzie miał liczbę 0 (nie istnieje) lub liczbę 1 (istnieje)
PoorLuzer
źródło
7
Która z dokumentacji SQLite obejmuje te tabele systemowe?
Paweł Veselov
29
@Pawel Veselov: Sekcja zatytułowana „Format pliku dla baz danych SQLite”: sqlite.org/fileformat2.html
Bryan Oakley
14
Nie będzie to jednak działać w przypadku tabel TEMP. Tabele TEMP znajdują się w „sqlite_temp_master”.
PatchyFog,
11
Czy to zwraca wartość logiczną? Co zwraca, jeśli tabela istnieje lub nie istnieje?
Dagrooms
8
@Dagrooms Zwróci listę tabel o podanej nazwie; to znaczy kursor będzie miał liczbę 0 (nie istnieje) lub liczbę 1 (istnieje).
Rein S
555

Jeśli używasz SQLite w wersji 3.3+, możesz łatwo utworzyć tabelę za pomocą:

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

W ten sam sposób możesz usunąć tabelę, tylko jeśli istnieje, używając:

drop table if exists TableName
Arthur Johnston
źródło
3
Zauważ, że create tableinstrukcja jest niekompletna (brakuje specyfikacji kolumn tabeli).
Eric Platon
11
istnieje również podobna konstrukcja dla indeksów: utwórz indeks, jeśli nie istnieje TableName_col1 na TableName (col1)
lowtech
26
To nie powinna być zaakceptowana odpowiedź, ale byłoby, gdyby pytanie brzmiało inaczej. OP nie zapytał, jak sprawdzić tabelę przed upuszczeniem lub utworzeniem. Co zrobić, jeśli musisz wykonać zapytanie do tabeli, która prawdopodobnie nie istnieje? Z tym problemem mam teraz do czynienia, a zaakceptowana odpowiedź działa najlepiej w tym ogólnym opisie problemu. To dobra szybka alternatywa.
Dagrooms
@Dagrooms, możesz mieć rację. Chociaż OP nie zadał tego pytania, szukałem tej odpowiedzi :)
earik87
169

Odmianą byłoby użycie SELECT COUNT (*) zamiast SELECT NAME, tj

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

Zwróci 0, jeśli tabela nie istnieje, 1 jeśli tak. Jest to prawdopodobnie przydatne w programowaniu, ponieważ wynik liczbowy jest szybszy / łatwiejszy do przetworzenia. Poniżej pokazano, jak można to zrobić w systemie Android za pomocą SQLiteDatabase, Cursor, rawQuery z parametrami.

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;
}
Stephen Quan
źródło
33
Wierzę, że „WYBIERZ 1” byłby jeszcze szybszy.
PatchyFog,
Dlaczego kursor.getInt (0) jest równy liczbie rekordów w bazie danych?
Siemion Daniłow
1
Liczymy, ile razy TABELA pojawia się w schemacie sqlite. Liczba 0 oznacza, że ​​tabela nie istnieje. Liczba 1 oznacza, że ​​tabela istnieje. Są to jedyne dwie oczekiwane wartości liczby.
Stephen Quan
1
Chociaż liczba (z COUNT(*)) jest łatwa do przetworzenia, jeszcze łatwiej jest zwrócić istnienie wiersza lub nie; jeśli jest tam rząd, to istnieje, jeśli nie ma żadnego wiersza, to nie. (Już sprawdziłeś awarię w moveToFirst, więc praca zostałaby wykonana w tym momencie.)
dash-tom-bang
Zaktualizuj kod, aby zamknąć kursor, zanim zwrócisz wartość false.
Dave Thomas
43

Możesz spróbować:

SELECT name FROM sqlite_master WHERE name='table_name'
Galwański
źródło
4
type = stół byłby przydatny tho
mafu
Jeśli używasz C #, nie używaj tego polecenia w SQLiteReader reader = cmd.ExecuteReader();i wykonaj a dt.Load(reader)(gdzie dtjest a DataTable). Odkryłem, że daje to Object reference is not an instance of an objectwyjątek, .Load()jeśli tabela nie zostanie znaleziona. Zamiast tego użyj a SQLiteDataAdapter adapter = new SQLiteDataAdapter(cmd); i do adapter.Fill(ds), gdzie dsjest DataSet. Następnie możesz sprawdzić, czy ds.Tables.Count > 0i return ds.Tables[0];jeśli tak (lub else return null). Następnie możesz to sprawdzić DataTableza bycie null, jeśli dt.Rows != nulli jeślidt.Rows.Count>0
vapcguy
34

Posługiwać się:

PRAGMA table_info(your_table_name)

Jeśli wynikowa tabela jest pusta, wówczas your_table_namenie istnieje.

Dokumentacja:

PRAGMA schema.table_info (nazwa tabeli);

Ta pragma zwraca jeden wiersz dla każdej kolumny w nazwanej tabeli. Kolumny w zestawie wyników zawierają nazwę kolumny, typ danych, czy kolumna może mieć wartość NULL, oraz wartość domyślną dla kolumny. Kolumna „pk” w zestawie wyników wynosi zero dla kolumn, które nie są częścią klucza podstawowego, i jest indeksem kolumny w kluczu podstawowym dla kolumn, które są częścią klucza podstawowego.

Tabela nazwana w pragma table_info może być również widokiem.

Przykładowe dane wyjściowe:

cid|name|type|notnull|dflt_value|pk
0|id|INTEGER|0||1
1|json|JSON|0||0
2|name|TEXT|0||0
Diego Vélez
źródło
Jest to świetny sposób na ustalenie, czy tabela istnieje w Pythonie.
Michael Murphy,
lub Xamarin Forms
SerenityNow
4
Jest to świetny sposób na programowe uzyskanie definicji kolumn
w00t
33

Nazwy tabel SQLite nie rozróżniają wielkości liter, ale w porównaniu domyślnie rozróżniana jest wielkość liter. Aby to działało poprawnie we wszystkich przypadkach, musisz dodać COLLATE NOCASE.

SELECT name FROM sqlite_master WHERE type='table' AND name='table_name' COLLATE NOCASE
Brice M. Dempsey
źródło
33

Jeśli pojawia się błąd „Tabela już istnieje”, wprowadź zmiany w łańcuchu SQL, jak poniżej:

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

W ten sposób możesz uniknąć wyjątków.

Rakesh Chaudhari
źródło
32

Zobacz to :

SELECT name FROM sqlite_master
WHERE type='table'
ORDER BY name;
Anton Gogolev
źródło
23

Jeśli używasz fmdb , myślę, że możesz po prostu zaimportować FMDatabaseAdditions i użyć funkcji bool:

[yourfmdbDatabase tableExists:tableName].
użytkownik655489
źródło
1
Pamiętaj, aby zaimportować plik „FMDatabaseAdditions.h”, aby skorzystać z tej metody, w przeciwnym razie będziesz się zastanawiać, dlaczego ją usunęli! :)
Czy
Chociaż może to być poprawna odpowiedź, pytanie dotyczyło sqlite, a nie konkretnej biblioteki w danym języku. Myślę, że odpowiedzią powinno być podanie kodu SQL, a nie wywołanie jednej z metod biblioteki
nacho4d
13

Poniższy kod zwraca 1, jeśli tabela istnieje, lub 0, jeśli tabela nie istnieje.

SELECT CASE WHEN tbl_name = "name" THEN 1 ELSE 0 END FROM sqlite_master WHERE tbl_name = "name" AND type = "table"
Pacheco
źródło
1
To nadal nie zwróci niczego, jeśli tabela nie istnieje, ponieważ warunek where uniemożliwia wynik.
David Gausmann
10

Pamiętaj, że aby sprawdzić, czy tabela istnieje w bazie danych TEMP, musisz użyć sqlite_temp_masterzamiast sqlite_master:

SELECT name FROM sqlite_temp_master WHERE type='table' AND name='table_name';
Scott Deerwester
źródło
9

Oto funkcja, której użyłem:

Biorąc pod uwagę SQLDatabase Object = db

public boolean exists(String table) {
    try {
         db.query("SELECT * FROM " + table);
         return true;
    } catch (SQLException e) {
         return false;
    }
}
DroidGrailer
źródło
1
Niestety musiałem użyć tego w mojej aplikacji na Androida, ponieważ odkryłem, że urządzenia Samsung nie używają standardowej struktury tabeli sqlite_master, z którą wszyscy inni pracują.
Anthony Chuinard
7

Użyj tego kodu:

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

Jeśli zwrócona liczba tablic jest równa 1, oznacza to, że tabela istnieje. W przeciwnym razie nie istnieje.

asmad
źródło
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

Uwaga: Działa to teraz na moim komputerze Mac z Python 3.7.1

Douglas Goodall
źródło
Wygląda to na czystsze niż wszystkie inne odpowiedzi .. Dziękuję !!
Harsha Vardhan
Nie działa dla mnie: muszę usunąć nawiasy {} wokół table_name, a potem jest w porządku.
Banan
1
Upewnij się, że table_namenie jest dostarczany z nieprzetworzonego źródła (np. Danych wejściowych użytkownika), w przeciwnym razie będzie podatny na wstrzyknięcie SQL. Zawsze lepiej jest używać parametrów zamiast technik manipulacji tekstem
od
3

Posługiwać się

SELECT 1 FROM table LIMIT 1;

aby zapobiec odczytaniu wszystkich rekordów.

Franz Fahrenkrog Petermann
źródło
Zwraca NULL, jeśli tabela istnieje, ale nie ma żadnych rekordów.
radiospiel
Jeśli tabela nie istnieje, wygeneruje błąd. Złap to, a wiesz, że to nie istnieje.
luckydonald
stosowanie obsługi błędów jako kontroli przepływu zasadniczo nie jest uważane za najlepszą praktykę. Tego prawdopodobnie należy unikać.
Jeff Woodard
3

Możesz napisać następujące zapytanie, aby sprawdzić istnienie tabeli.

SELECT name FROM sqlite_master WHERE name='table_name'

Tutaj „nazwa_tabeli” to nazwa tabeli, którą utworzyłeś. Na przykład

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

i zaznacz

  SELECT name FROM sqlite_master WHERE name='country'
akn
źródło
6
Czym różni się to od już zaakceptowanej, wysoko ocenionej odpowiedzi sprzed 9 lat?
Kevin Van Dyck
3

Najbardziej niezawodny sposób, jaki znalazłem w C #, teraz przy użyciu najnowszego pakietu nuget sqlite-net-pcl (1.5.231), który używa SQLite 3, jest następujący:

var result = database.GetTableInfo(tableName);
if ((result == null) || (result.Count == 0))
{
    database.CreateTable<T>(CreateFlags.AllImplicit);
}
Matthew Joughin
źródło
2

Korzystanie z prostego zapytania SELECT jest - moim zdaniem - dość niezawodne. Przede wszystkim może sprawdzić istnienie tabeli w wielu różnych typach baz danych (SQLite / MySQL).

SELECT 1 FROM table;

Ma sens, gdy można użyć innego niezawodnego mechanizmu do ustalenia, czy zapytanie zakończyło się powodzeniem (na przykład zapytanie do bazy danych za pośrednictwem QSqlQuery w Qt ).

Grz
źródło
1

Funkcja c ++ sprawdza db i wszystkie dołączone bazy danych pod kątem istnienia tabeli i (opcjonalnie) kolumny.

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;
}

Edycja: Niedawno odkryłem funkcję sqlite3_table_column_metadata. W związku z tym

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;}
NoComprende
źródło
public static boolean tableExists (baza danych SQLiteDatabase, ciąg nazwa_tabeli) {return database.rawQuery ("WYBIERZ nazwę od sqlite_master GDZIE typ = 'table' AND name = '" + nazwa tabeli + +' ', null) .moveToFirst (); }
nick
Bardzo nieefektywny i ryzykowny sposób, ponieważ konkatenacja łańcuchów może skończyć na wszystkim.
Andrea Moro
0

Oto mój kod dla 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");
    }
});

I kolejny:

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);
        });
    });
}
Zappescu
źródło
0

Pomyślałem, że postawię moje 2 centy na tę dyskusję, nawet jeśli jest ona raczej stara. To zapytanie zwraca skalar 1, jeśli tabela istnieje, a 0 w przeciwnym razie.

select 
    case when exists 
        (select 1 from sqlite_master WHERE type='table' and name = 'your_table') 
        then 1 
        else 0 
    end as TableExists
Piotr Rodak
źródło
0

Tabela istnieje szybko lub nie w bazie danych

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)
    }
CSE 1994
źródło