Come posso verificare in SQLite se esiste una tabella?


895

Come posso verificare in modo affidabile in SQLite se esiste una tabella utente specifica?

Non sto chiedendo modi inaffidabili come verificare se un "select *" sulla tabella ha restituito un errore o meno (è anche una buona idea?).

Il motivo è così:

Nel mio programma, devo creare e quindi popolare alcune tabelle se non esistono già.

Se esistono già, devo aggiornare alcune tabelle.

Dovrei invece prendere qualche altro percorso per segnalare che le tabelle in questione sono già state create, ad esempio creando / mettendo / impostando un determinato flag nel mio file di inizializzazione / impostazioni del mio programma sul disco o qualcosa del genere?

O il mio approccio ha senso?


SQLite genererà un'eccezione se la tabella in una selezione non esiste. Semplicemente non c'è bisogno di altro lavoro di fantasia.
NoChance,

34
@NoChance lo sarà, ma lo sarà anche un numero qualsiasi di altre cose. È un po 'come vedere se quell'albero è davvero lì guidando in avanti con gli occhi chiusi, lo scoprirai in un modo o nell'altro :)
randomsock,

@randomsock, bell'esempio, ma un po 'spaventoso, specialmente se l'auto fosse la mia macchina ...
NoChance,

@randomsock, non so quale sia la convenzione sqlite, ma è più pitone chiedere perdono che permesso. cioè prendere l'eccezione invece di usare un condizionale.
Eric,

1
@Eric A partire da ora, la domanda non riguarda Python, ma supponendo che lo abbia fatto, l'errore è un generico sqlite3.OperationalError, quindi devi analizzare il messaggio di errore per assicurarti che sia, ad esempio, il messaggio "table TABLE_NAME già esiste" quando crei una tabella e, in caso contrario, azzerare l'errore e penso che non vi sia alcuna garanzia che il fraseggio dell'errore non cambierà.
Markus von Broady,

Risposte:


1023

Ho perso quella voce FAQ.

Ad ogni modo, per riferimento futuro, la query completa è:

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

Dov'è {table_name}il nome della tabella da controllare.

Sezione documentazione per riferimento: Formato file database. 2.6. Archiviazione dello schema del database SQL

  • Ciò restituirà un elenco di tabelle con il nome specificato; cioè, il cursore avrà un conteggio di 0 (non esiste) o un conteggio di 1 (esiste)

7
Quale della documentazione di SQLite copre queste tabelle di sistema?
Pawel Veselov,

29
@Pawel Veselov: la sezione intitolata "Formato file per database SQLite": sqlite.org/fileformat2.html
Bryan Oakley,

14
Tuttavia, ciò non funzionerà per le tabelle TEMP. Le tabelle TEMP sono in "sqlite_temp_master".
PatchyFog,

11
Questo restituisce un valore booleano? Cosa restituisce se la tabella esiste o non esiste?
Dagrooms,

8
@Dagrooms Questo restituirà un elenco di tabelle con il nome specificato; cioè, il cursore avrà un conteggio di 0 (non esiste) o un conteggio di 1 (esiste).
Rein S

555

Se si utilizza SQLite versione 3.3+, è possibile creare facilmente una tabella con:

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

Allo stesso modo, è possibile rimuovere una tabella solo se esiste utilizzando:

drop table if exists TableName

3
Si noti che l' create tableistruzione è incompleta (manca la specifica delle colonne della tabella).
Eric Platon,

11
esiste anche un costrutto simile per gli indici: crea indice se non esiste TableName_col1 su TableName (col1)
lowtech

26
Questa non dovrebbe essere la risposta accettata, ma sarebbe se la domanda fosse formulata diversamente. L'OP non ha chiesto come controllare una tabella prima di abbandonare o creare. E se dovessi interrogare una tabella che forse non esiste? Questo è il problema che sto affrontando ora e la risposta accettata funziona meglio in questa dichiarazione generale del problema. Questa è una buona alternativa veloce.
Dagrooms,

@Dagrooms, potresti avere ragione. Anche se l'OP non ha chiesto questo, stavo cercando questa risposta :)
earik87,

169

Una variante sarebbe quella di utilizzare SELECT COUNT (*) invece di SELECT NAME, ovvero

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

Ciò restituirà 0, se la tabella non esiste, 1 se esiste. Ciò è probabilmente utile nella programmazione poiché un risultato numerico è più rapido / facile da elaborare. Di seguito viene illustrato come eseguire questa operazione in Android utilizzando SQLiteDatabase, Cursor, rawQuery con parametri.

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
Credo che un "SELEZIONA 1" sarebbe ancora più veloce.
PatchyFog

Perché cursore.getInt (0) è uguale al conteggio dei record nel database?
Semyon Danilov,

1
Stiamo contando il numero di volte in cui la TABELLA appare nello schema sqlite. Un conteggio di 0 indica che la tabella non esiste. Un conteggio di 1 indica che la tabella esiste. Questi sono gli unici due valori attesi di conteggio.
Stephen Quan,

1
Mentre il numero (da COUNT(*)) è facile da elaborare, è ancora più semplice restituire l'esistenza di una riga o meno; se c'è una riga lì allora esiste, se non c'è nessuna riga non lo è. (Hai già verificato la presenza di errori in moveToFirst, quindi il lavoro sarebbe stato svolto a quel punto.)
dash-tom-bang

Aggiorna il codice per chiudere il cursore prima di restituire false.
Dave Thomas,

43

Puoi provare:

SELECT name FROM sqlite_master WHERE name='table_name'

4
type = table sarebbe utile anche se
mafu

Se usi C #, non usare questo comando in a SQLiteReader reader = cmd.ExecuteReader();ed esegui un dt.Load(reader)(dove dtè a DataTable). Ho trovato che dà questa Object reference is not an instance of an objecteccezione sul .Load()se la tabella non viene trovata. Invece, usa a SQLiteDataAdapter adapter = new SQLiteDataAdapter(cmd); e do adapter.Fill(ds), dove dsè a DataSet. È quindi possibile vedere se ds.Tables.Count > 0e return ds.Tables[0];se sì (o else return null). Quindi puoi verificarlo DataTableper essere null, se dt.Rows != nulle sedt.Rows.Count>0
vapcguy,

34

Uso:

PRAGMA table_info(your_table_name)

Se la tabella risultante è vuota, allora your_table_namenon esiste.

Documentazione:

PRAGMA schema.table_info (nome-tabella);

Questo pragma restituisce una riga per ogni colonna nella tabella denominata. Le colonne nel set di risultati includono il nome della colonna, il tipo di dati, indipendentemente dal fatto che la colonna possa essere NULL e il valore predefinito per la colonna. La colonna "pk" nel set di risultati è zero per le colonne che non fanno parte della chiave primaria ed è l'indice della colonna nella chiave primaria per le colonne che fanno parte della chiave primaria.

La tabella denominata nel pragma table_info può anche essere una vista.

Esempio di output:

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

Questo è un ottimo modo per determinare se esiste una tabella in Python.
Michael Murphy,

o Xamarin Forms
SerenityNow

4
Questo è un ottimo modo per ottenere programmaticamente le definizioni di colonna
w00t

33

I nomi delle tabelle SQLite non fanno distinzione tra maiuscole e minuscole, ma il confronto è case sensitive per impostazione predefinita. Per farlo funzionare correttamente in tutti i casi è necessario aggiungere COLLATE NOCASE.

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

33

Se viene visualizzato l'errore "tabella già esistente", apportare modifiche nella stringa SQL come di seguito:

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

In questo modo è possibile evitare le eccezioni.



23

Se stai usando fmdb , penso che puoi semplicemente importare FMDatabaseAdditions e usare la funzione bool:

[yourfmdbDatabase tableExists:tableName].

1
Assicurati di importare "FMDatabaseAdditions.h" per utilizzare questo metodo, altrimenti ti chiederai perché l'hanno rimosso! :)
Will

Sebbene questa potrebbe essere una risposta corretta, la domanda riguardava sqlite non una libreria particolare in una lingua particolare. Penso che la risposta dovrebbe essere quella di fornire il codice sql, non una chiamata a uno dei metodi della libreria
nacho4d

13

Il codice seguente restituisce 1 se la tabella esiste o 0 se la tabella non esiste.

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

1
Ciò non restituirà nulla se la tabella non esiste, poiché la condizione where impedisce qualsiasi risultato.
David Gausmann,

10

Si noti che per verificare se esiste una tabella nel database TEMP, è necessario utilizzare sqlite_temp_masterinvece di sqlite_master:

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

9

Ecco la funzione che ho usato:

Dato un oggetto SQLDatabase = db

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

1
Ho dovuto purtroppo usare questo nella mia app per Android poiché ho scoperto che i dispositivi Samsung non usano la struttura di tabella sqlite_master standard con cui tutti gli altri stanno lavorando.
Anthony Chuinard,

7

Usa questo codice:

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

Se il conteggio degli array restituito è uguale a 1 significa che la tabella esiste. Altrimenti non esiste.


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

Nota: ora funziona sul mio Mac con Python 3.7.1


Questo sembra più pulito di tutte le altre risposte .. Grazie !!
Harsha Vardhan,

Per me non funziona: devo cancellare le parentesi {} attorno a table_name, quindi va bene.
Banana,

1
Assicurarsi che table_namenon sia fornito da una fonte non trattata (come l'input dell'utente), altrimenti sarà vulnerabile all'iniezione SQL. È sempre meglio usare i parametri invece delle tecniche di manipolazione del testo
astef

3

Uso

SELECT 1 FROM table LIMIT 1;

per impedire la lettura di tutti i record.


Ciò restituisce NULL se la tabella esiste ma non ha alcun record.
radiospiel,

Se la tabella non esiste, verrà generato un errore. Cattura quello e sai che non esiste.
luckydonald

l'uso della gestione degli errori come controllo del flusso non è generalmente considerato la migliore pratica. Questo dovrebbe probabilmente essere evitato.
Jeff Woodard,

3

È possibile scrivere la seguente query per verificare l'esistenza della tabella.

SELECT name FROM sqlite_master WHERE name='table_name'

Qui 'table_name' è il nome della tabella che cosa hai creato. Per esempio

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

e controlla

  SELECT name FROM sqlite_master WHERE name='country'

6
In che modo si differenzia dalla risposta già accettata per votazione superiore di 9 anni fa?
Kevin Van Dyck,

3

Il modo più affidabile che ho trovato in C # in questo momento, usando l'ultimo pacchetto nuget sqlite-net-pcl (1.5.231) che utilizza SQLite 3, è il seguente:

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

2

L'utilizzo di una semplice query SELECT è - a mio avviso - abbastanza affidabile. Soprattutto può controllare l'esistenza della tabella in molti diversi tipi di database (SQLite / MySQL).

SELECT 1 FROM table;

Ha senso quando è possibile utilizzare altri meccanismi affidabili per determinare se la query ha avuto esito positivo (ad esempio, si esegue una query su un database tramite QSqlQuery in Qt ).


1

La funzione c ++ controlla db e tutti i database collegati per l'esistenza della tabella e (facoltativamente) della colonna.

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

Modifica: recentemente scoperta la funzione sqlite3_table_column_metadata. Quindi

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

tabella booleana statica pubblicaExists (database SQLiteDatabase, String tableName) {return database.rawQuery ("SELEZIONA nome DA sqlite_master DOVE tipo = 'table' AND name = '" + tableName + "'", null) .moveToFirst (); }
nick

Modo molto inefficiente e rischioso poiché la concatenazione di stringhe può finire per tutto.
Andrea Moro,

0

Questo è il mio codice per 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");
    }
});

E l'altro:

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

Ho pensato di mettere i miei 2 centesimi in questa discussione, anche se è piuttosto vecchio .. Questa query restituisce lo scalare 1 se la tabella esiste e 0 altrimenti.

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

0

La tabella esiste o no nel database 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)
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.