Wie überprüfe ich in SQLite, ob eine Tabelle vorhanden ist?

893

Wie überprüfe ich in SQLite zuverlässig , ob eine bestimmte Benutzertabelle vorhanden ist?

Ich frage nicht nach unzuverlässigen Methoden wie der Überprüfung, ob ein "select *" in der Tabelle einen Fehler zurückgegeben hat oder nicht (ist dies überhaupt eine gute Idee?).

Der Grund ist wie folgt:

In meinem Programm muss ich einige Tabellen erstellen und dann füllen, wenn sie noch nicht vorhanden sind.

Wenn sie bereits vorhanden sind, muss ich einige Tabellen aktualisieren.

Sollte ich stattdessen einen anderen Weg einschlagen, um zu signalisieren, dass die betreffenden Tabellen bereits erstellt wurden - beispielsweise durch Erstellen / Setzen / Setzen eines bestimmten Flags in meiner Programminitialisierungs- / Einstellungsdatei auf der Festplatte oder so?

Oder macht mein Ansatz Sinn?

PoorLuzer
quelle
SQLite löst eine Ausnahme aus, wenn die Tabelle in einer Auswahl nicht vorhanden ist. Es besteht einfach keine Notwendigkeit mehr für ausgefallene Arbeiten.
NoChance
34
@NoChance wird es, aber auch eine Reihe anderer Dinge. Das ist ein bisschen so, als würde man sehen, ob dieser Baum wirklich da ist, indem man mit geschlossenen Augen vorwärts fährt. Man findet es auf die eine oder andere Weise heraus :)
Randomsock
@randomsock, schönes Beispiel, aber ein bisschen beängstigend, besonders wenn das Auto mein Auto wäre ...
NoChance
@randomsock, ich weiß nicht, was die SQLite-Konvention ist, aber es ist pythonischer, um Vergebung als um Erlaubnis zu bitten. dh die Ausnahme abfangen, anstatt eine Bedingung zu verwenden.
Eric
1
@Eric Ab sofort betrifft die Frage nicht Python, aber unter der Annahme, dass dies der Fall ist, handelt es sich um einen generischen Fehler. sqlite3.OperationalErrorSie müssen die Fehlermeldung analysieren, um sicherzustellen, dass es sich beim Erstellen beispielsweise um die Meldung "Tabelle TABLE_NAME ist bereits vorhanden" handelt eine Tabelle, und wenn nicht, erhöhen Sie den Fehler und ich denke, es gibt keine Garantie, dass sich die Formulierung des Fehlers nicht ändert.
Markus von Broady

Antworten:

1021

Ich habe diesen FAQ-Eintrag verpasst.

Zum späteren Nachschlagen lautet die vollständige Abfrage wie folgt:

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

Wo {table_name} ist der Name der zu überprüfenden Tabelle?

Dokumentationsabschnitt als Referenz: Datenbankdateiformat. 2.6. Speicherung des SQL-Datenbankschemas

  • Dies gibt eine Liste von Tabellen mit dem angegebenen Namen zurück. Das heißt, der Cursor hat eine Anzahl von 0 (existiert nicht) oder eine Anzahl von 1 (existiert nicht).
PoorLuzer
quelle
7
Welche SQLite-Dokumentation behandelt diese Systemtabellen?
Pawel Veselov
29
@ Pawel Veselov: Der Abschnitt mit dem Titel "Dateiformat für SQLite-Datenbanken": sqlite.org/fileformat2.html
Bryan Oakley
14
Dies funktioniert jedoch nicht für TEMP-Tabellen. TEMP-Tabellen befinden sich in "sqlite_temp_master".
PatchyFog
11
Gibt dies einen Booleschen Wert zurück? Was gibt es zurück, wenn die Tabelle existiert oder nicht?
Dagrooms
8
@Dagrooms Dies gibt eine Liste von Tabellen mit dem angegebenen Namen zurück. Das heißt, der Cursor hat eine Anzahl von 0 (existiert nicht) oder eine Anzahl von 1 (existiert nicht).
Rein S
555

Wenn Sie SQLite Version 3.3+ verwenden, können Sie ganz einfach eine Tabelle erstellen mit:

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

Auf die gleiche Weise können Sie eine Tabelle nur entfernen, wenn sie vorhanden ist, indem Sie Folgendes verwenden:

drop table if exists TableName
arthur johnston
quelle
3
Beachten Sie, dass die create tableAnweisung unvollständig ist (die Tabellenspaltenspezifikation fehlt).
Eric Platon
11
Es gibt auch ein ähnliches Konstrukt für Indizes: Index erstellen, falls nicht vorhanden TableName_col1 auf TableName (col1)
Lowtech
26
Dies sollte nicht die akzeptierte Antwort sein, würde aber, wenn die Frage anders formuliert wäre. Das OP hat nicht gefragt, wie eine Tabelle vor dem Löschen oder Erstellen überprüft werden soll. Was ist, wenn Sie eine Tabelle abfragen müssen, die möglicherweise nicht vorhanden ist? Dies ist das Problem, mit dem ich jetzt konfrontiert bin, und die akzeptierte Antwort funktioniert am besten in dieser allgemeinen Problemstellung. Dies ist eine gute schnelle Alternative.
Dagrooms
@Dagrooms, vielleicht hast du recht. Obwohl das OP dies nicht fragte, suchte ich nach dieser Antwort :)
earik87
169

Eine Variation wäre, SELECT COUNT (*) anstelle von SELECT NAME zu verwenden, d. H.

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

Dies gibt 0 zurück, wenn die Tabelle nicht vorhanden ist, 1, wenn dies der Fall ist. Dies ist wahrscheinlich bei Ihrer Programmierung hilfreich, da ein numerisches Ergebnis schneller / einfacher zu verarbeiten ist. Im Folgenden wird veranschaulicht, wie Sie dies in Android mithilfe von SQLiteDatabase, Cursor, rawQuery mit Parametern tun würden.

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
quelle
33
Ich glaube, eine "SELECT 1" wäre noch schneller.
PatchyFog
Warum entspricht cursor.getInt (0) der Anzahl der Datensätze in der Datenbank?
Semyon Danilov
1
Wir zählen, wie oft die TABELLE im SQLite-Schema angezeigt wird. Eine Zählung von 0 bedeutet, dass die Tabelle nicht existiert. Eine Zählung von 1 bedeutet, dass die Tabelle vorhanden ist. Dies sind die einzigen zwei erwarteten Zählwerte.
Stephen Quan
1
Während die Zahl (von COUNT(*)) einfach zu verarbeiten ist, ist es noch einfacher, die Existenz einer Zeile zurückzugeben oder nicht; Wenn es dort eine Zeile gibt, existiert sie, wenn es keine Zeile gibt, existiert sie nicht. (Sie überprüfen bereits in moveToFirst, ob ein Fehler aufgetreten ist, damit die Arbeit an diesem Punkt erledigt ist.)
dash-tom-bang
Bitte aktualisieren Sie Ihren Code, um den Cursor zu schließen, bevor Sie false zurückgeben.
Dave Thomas
43

Du könntest es versuchen:

SELECT name FROM sqlite_master WHERE name='table_name'
Galwegisch
quelle
4
Typ = Tabelle wäre nützlich,
wenn
Wenn Sie C # verwenden, verwenden Sie diesen Befehl nicht in a SQLiteReader reader = cmd.ExecuteReader();und führen Sie a aus dt.Load(reader)(wo dtist a DataTable). Ich habe festgestellt, dass es diese Object reference is not an instance of an objectAusnahme gibt, .Load()wenn die Tabelle nicht gefunden wird. Verwenden Sie stattdessen a SQLiteDataAdapter adapter = new SQLiteDataAdapter(cmd); und do adapter.Fill(ds), wo dsist a DataSet. Sie können dann sehen, ob ds.Tables.Count > 0und return ds.Tables[0];ob ja (oder else return null). Dann können Sie , dass der Check DataTablefür sein null, wenn dt.Rows != null, und wenndt.Rows.Count>0
vapcguy
34

Verwenden:

PRAGMA table_info(your_table_name)

Wenn die resultierende Tabelle leer your_table_nameist, existiert sie nicht.

Dokumentation:

PRAGMA schema.table_info (Tabellenname);

Dieses Pragma gibt eine Zeile für jede Spalte in der benannten Tabelle zurück. Zu den Spalten in der Ergebnismenge gehören der Spaltenname, der Datentyp, ob die Spalte NULL sein kann oder nicht, und der Standardwert für die Spalte. Die Spalte "pk" in der Ergebnismenge ist Null für Spalten, die nicht Teil des Primärschlüssels sind, und der Index der Spalte im Primärschlüssel für Spalten, die Teil des Primärschlüssels sind.

Die im Pragma table_info genannte Tabelle kann auch eine Ansicht sein.

Beispielausgabe:

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
quelle
Auf diese Weise können Sie feststellen, ob in Python eine Tabelle vorhanden ist.
Michael Murphy
oder Xamarin Forms
SerenityNow
4
Dies ist eine großartige Möglichkeit, programmgesteuert zu den
Spaltendefinitionen
33

Bei SQLite-Tabellennamen wird die Groß- und Kleinschreibung nicht berücksichtigt, beim Vergleich wird jedoch standardmäßig zwischen Groß- und Kleinschreibung unterschieden. Damit dies in allen Fällen ordnungsgemäß funktioniert, müssen Sie hinzufügen COLLATE NOCASE.

SELECT name FROM sqlite_master WHERE type='table' AND name='table_name' COLLATE NOCASE
Brice M. Dempsey
quelle
33

Wenn der Fehler "Tabelle existiert bereits" angezeigt wird, nehmen Sie die folgenden Änderungen an der SQL-Zeichenfolge vor:

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

Auf diese Weise können Sie die Ausnahmen vermeiden.

Rakesh Chaudhari
quelle
32

Siehe dies :

SELECT name FROM sqlite_master
WHERE type='table'
ORDER BY name;
Anton Gogolev
quelle
23

Wenn Sie fmdb verwenden , können Sie einfach FMDatabaseAdditions importieren und die Bool-Funktion verwenden:

[yourfmdbDatabase tableExists:tableName].
user655489
quelle
1
Stellen Sie sicher, dass Sie "FMDatabaseAdditions.h" importieren, um diese Methode zu verwenden, sonst werden Sie sich fragen, warum sie sie entfernt haben! :)
Will
Obwohl dies eine richtige Antwort sein könnte, ging es bei der Frage um SQLite, nicht um eine bestimmte Bibliothek in einer bestimmten Sprache. Ich denke, die Antwort sollte sein, SQL-Code bereitzustellen, nicht einen Aufruf einer der Methoden der Bibliothek
nacho4d
13

Der folgende Code gibt 1 zurück, wenn die Tabelle vorhanden ist, oder 0, wenn die Tabelle nicht vorhanden ist.

SELECT CASE WHEN tbl_name = "name" THEN 1 ELSE 0 END FROM sqlite_master WHERE tbl_name = "name" AND type = "table"
Pacheco
quelle
1
Dies gibt immer noch nichts zurück, wenn die Tabelle nicht vorhanden ist, da die where-Bedingung ein Ergebnis verhindert.
David Gausmann
10

Beachten Sie, dass zu prüfen , ob eine Tabelle in der TEMP - Datenbank vorhanden ist , müssen Sie verwenden sqlite_temp_masterstatt sqlite_master:

SELECT name FROM sqlite_temp_master WHERE type='table' AND name='table_name';
Scott Deerwester
quelle
9

Hier ist die Funktion, die ich verwendet habe:

Gegeben ein SQLDatabase-Objekt = db

public boolean exists(String table) {
    try {
         db.query("SELECT * FROM " + table);
         return true;
    } catch (SQLException e) {
         return false;
    }
}
DroidGrailer
quelle
1
Ich musste dies leider in meiner Android-App verwenden, da ich feststellte, dass Samsung-Geräte nicht die Standard-Tabellenstruktur sqlite_master verwenden, mit der alle anderen arbeiten.
Anthony Chuinard
7

Verwenden Sie diesen Code:

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

Wenn die Anzahl der zurückgegebenen Arrays gleich 1 ist, bedeutet dies, dass die Tabelle vorhanden ist. Sonst existiert es nicht.

asmad
quelle
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

Hinweis: Dies funktioniert jetzt auf meinem Mac mit Python 3.7.1

Douglas Goodall
quelle
Das sieht sauberer aus als alle anderen Antworten. Danke !!
Harsha Vardhan
Funktioniert bei mir nicht: Ich muss die {} Klammern um table_name löschen, dann ist es in Ordnung.
Banane
1
table_nameStellen Sie sicher, dass es nicht aus einer nicht verwendeten Quelle stammt (wie Benutzereingaben), da es sonst für SQL-Injection anfällig ist. Es ist immer besser, Parameter anstelle von Textmanipulationstechniken zu verwenden
astef
3

Verwenden

SELECT 1 FROM table LIMIT 1;

um zu verhindern, dass alle Datensätze gelesen werden.

Franz Fahrenkrog Petermann
quelle
Dies gibt NULL zurück, wenn die Tabelle vorhanden ist, aber keine Datensätze enthält.
Radiospiel
Wenn die Tabelle nicht vorhanden ist, wird ein Fehler ausgegeben. Fangen Sie das, und Sie wissen, dass es nicht existiert.
Luckydonald
Die Verwendung der Fehlerbehandlung als Flusskontrolle wird im Allgemeinen nicht als bewährte Methode angesehen. Dies sollte wahrscheinlich vermieden werden.
Jeff Woodard
3

Sie können die folgende Abfrage schreiben, um die Tabellenexistenz zu überprüfen.

SELECT name FROM sqlite_master WHERE name='table_name'

Hier ist 'Tabellenname' Ihr Tabellenname, den Sie erstellt haben. Zum Beispiel

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

und prüfe

  SELECT name FROM sqlite_master WHERE name='country'
akn
quelle
6
Inwiefern unterscheidet sich dies von der bereits akzeptierten Topvoted-Antwort von vor 9 Jahren?
Kevin Van Dyck
3

Der zuverlässigste Weg, den ich derzeit in C # gefunden habe, mit dem neuesten sqlite-net-pcl-Nuget-Paket (1.5.231), das SQLite 3 verwendet, ist folgender:

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

Die Verwendung einer einfachen SELECT-Abfrage ist meiner Meinung nach ziemlich zuverlässig. Vor allem kann es das Vorhandensein von Tabellen in vielen verschiedenen Datenbanktypen (SQLite / MySQL) überprüfen.

SELECT 1 FROM table;

Es ist sinnvoll, wenn Sie einen anderen zuverlässigen Mechanismus verwenden können, um festzustellen, ob die Abfrage erfolgreich war (z. B. wenn Sie eine Datenbank über QSqlQuery in abfragen) Qt ).

Grz
quelle
1

Die c ++ - Funktion überprüft die Datenbank und alle angehängten Datenbanken auf das Vorhandensein von Tabellen und (optional) Spalten.

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

Bearbeiten: Kürzlich wurde die Funktion sqlite3_table_column_metadata entdeckt. Daher

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
quelle
public static boolean tableExists (SQLiteDatabase-Datenbank, String tableName) {return database.rawQuery ("SELECT name FROM sqlite_master WHERE type = 'table' AND name = '" + tableName + "'", null) .moveToFirst (); }
Nick
Sehr ineffizient und riskant, da die Verkettung von Zeichenfolgen zu allem führen kann.
Andrea Moro
0

Dies ist mein Code für 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");
    }
});

Und die andere:

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
quelle
0

Ich dachte, ich würde meine 2 Cent in diese Diskussion stecken, auch wenn es ziemlich alt ist. Diese Abfrage gibt Skalar 1 zurück, wenn die Tabelle existiert, und 0 ansonsten.

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
quelle
0

Tabelle existiert oder nicht in der Datenbank in 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)
    }
CSE 1994
quelle