¿Cómo verifico en SQLite si existe una tabla?

895

¿Cómo puedo, de manera confiable , verifico en SQLite si existe una tabla de usuario en particular?

No estoy pidiendo formas poco confiables como verificar si un "select *" en la tabla devolvió un error o no (¿es incluso una buena idea?).

La razón es así:

En mi programa, necesito crear y luego llenar algunas tablas si aún no existen.

Si ya existen, necesito actualizar algunas tablas.

¿Debería tomar otra ruta para indicar que las tablas en cuestión ya se han creado, por ejemplo, creando / colocando / configurando un determinado indicador en el archivo de configuración / inicialización de mi programa en el disco o algo así?

¿O mi enfoque tiene sentido?

PobreLuzer
fuente
SQLite lanzará una excepción si la tabla en una selección no existe. Simplemente no hay necesidad de más trabajo sofisticado.
NoChance
34
@No es posible, pero también lo hará cualquier otra cantidad de cosas. Eso es un poco como ver si ese árbol está realmente allí conduciendo hacia adelante con los ojos cerrados, lo descubrirá de una forma u otra :)
randomsock
@randomsock, buen ejemplo, pero un poco aterrador, especialmente si el auto fuera mi auto ...
NoChance
@randomsock, no sé cuál es la convención sqlite, pero es más pitónico pedir perdón que permiso. es decir, captura la excepción en lugar de usar un condicional.
Eric
1
@Eric A partir de ahora, la pregunta no involucra a Python, pero suponiendo que lo haya hecho, el error es genérico sqlite3.OperationalError, por lo que debe analizar el mensaje de error para asegurarse de que es, por ejemplo, el mensaje "tabla TABLE_NAME ya existe" cuando crea una tabla, y si no, vuelva a plantear el error y creo que no hay garantía de que la redacción del error no cambie.
Markus von Broady

Respuestas:

1023

Me perdí esa entrada de preguntas frecuentes.

De todos modos, para referencia futura, la consulta completa es:

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

¿Dónde {table_name}está el nombre de la tabla para verificar?

Sección de documentación para referencia: Formato de archivo de base de datos. 2.6. Almacenamiento del esquema de base de datos SQL

  • Esto devolverá una lista de tablas con el nombre especificado; es decir, el cursor tendrá un recuento de 0 (no existe) o un recuento de 1 (sí existe)
PobreLuzer
fuente
77
¿Cuál de la documentación de SQLite cubre estas tablas del sistema?
Pawel Veselov
29
@Pawel Veselov: La sección titulada "Formato de archivo para bases de datos SQLite": sqlite.org/fileformat2.html
Bryan Oakley
14
Sin embargo, esto no funcionará para las tablas TEMP. Las tablas TEMP están en "sqlite_temp_master".
PatchyFog
11
¿Esto devuelve un booleano? ¿Qué devuelve si la tabla existe o no?
Dagrooms
8
@Dagrooms Esto devolverá una lista de tablas con el nombre especificado; es decir, el cursor tendrá un recuento de 0 (no existe) o un recuento de 1 (sí existe).
Rein S
555

Si está utilizando SQLite versión 3.3+, puede crear fácilmente una tabla con:

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

Del mismo modo, puede eliminar una tabla solo si existe mediante el uso de:

drop table if exists TableName
Arthur Johnston
fuente
3
Tenga en cuenta que la create tabledeclaración está incompleta (falta la especificación de las columnas de la tabla).
Eric Platon
11
también hay una construcción similar para los índices: crear índice si no existe TableName_col1 en TableName (col1)
lowtech
26
Esta no debería ser la respuesta aceptada, pero lo sería si la pregunta estuviera redactada de manera diferente. El OP no preguntó cómo verificar una tabla antes de soltarla o crearla. ¿Qué pasa si tiene que consultar una tabla que posiblemente no existe? Este es el problema que estoy enfrentando ahora, y la respuesta aceptada funciona mejor en esta declaración general del problema. Esta es una buena alternativa rápida.
Dagrooms
@Dagrooms, puede que tengas razón. Aunque el OP no preguntó esto, estaba buscando esta respuesta :)
earik87
169

Una variación sería usar SELECT COUNT (*) en lugar de SELECT NAME, es decir

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

Esto devolverá 0, si la tabla no existe, 1 si existe. Esto probablemente sea útil en su programación ya que un resultado numérico es más rápido / fácil de procesar. Lo siguiente ilustra cómo haría esto en Android usando SQLiteDatabase, Cursor, rawQuery con parámetros.

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
fuente
33
Creo que un "SELECCIONAR 1" sería aún más rápido.
PatchyFog
¿Por qué cursor.getInt (0) es igual al recuento de registros en la base de datos?
Semyon Danilov
1
Estamos contando la cantidad de veces que la TABLA aparece en el esquema sqlite. Un recuento de 0 significa que la tabla no existe. Un recuento de 1 significa que la tabla existe. Estos son los únicos dos valores esperados de conteo.
Stephen Quan el
1
Si bien el número (desde COUNT(*)) es fácil de procesar, es aún más fácil devolver la existencia de una fila o no; si hay una fila allí, entonces existe, si no hay fila, no existe. (Ya verifica si hay errores en moveToFirst, por lo que el trabajo se realizaría en ese punto.)
dash-tom-bang
Actualice su código para cerrar el cursor antes de devolver falso.
Dave Thomas
43

Tu podrías intentar:

SELECT name FROM sqlite_master WHERE name='table_name'
Galés
fuente
44
tipo = tabla sería útil aunque
mafu
Si usa C #, no use este comando en a SQLiteReader reader = cmd.ExecuteReader();y haga un dt.Load(reader)(donde dtes a DataTable). Encontré que da esta Object reference is not an instance of an objectexcepción .Load()si no se encuentra la tabla. En su lugar, use ay SQLiteDataAdapter adapter = new SQLiteDataAdapter(cmd); do adapter.Fill(ds), donde dses a DataSet. A continuación, puede ver si ds.Tables.Count > 0, y return ds.Tables[0];si es así (o else return null). Entonces puedes verificar eso DataTablepor ser null, si dt.Rows != nully sidt.Rows.Count>0
vapcguy
35

Utilizar:

PRAGMA table_info(your_table_name)

Si la tabla resultante está vacía, entonces your_table_nameno existe.

Documentación:

PRAGMA schema.table_info (nombre-tabla);

Este pragma devuelve una fila para cada columna en la tabla con nombre. Las columnas en el conjunto de resultados incluyen el nombre de la columna, el tipo de datos, si la columna puede ser NULL o no, y el valor predeterminado para la columna. La columna "pk" en el conjunto de resultados es cero para las columnas que no forman parte de la clave primaria, y es el índice de la columna en la clave primaria para las columnas que forman parte de la clave primaria.

La tabla nombrada en el pragma table_info también puede ser una vista.

Salida de ejemplo:

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
fuente
Esta es una excelente manera de determinar si existe una tabla en Python.
Michael Murphy
o Xamarin Forms
SerenityNow
44
Esta es una excelente manera de llegar a las definiciones de columna mediante programación
w00t
33

Los nombres de tabla de SQLite no distinguen entre mayúsculas y minúsculas, pero la comparación distingue entre mayúsculas y minúsculas de forma predeterminada. Para que esto funcione correctamente en todos los casos, debe agregar COLLATE NOCASE.

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

Si obtiene un error "la tabla ya existe", realice los cambios en la cadena de SQL como se muestra a continuación:

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

De esta manera puede evitar las excepciones.

Rakesh Chaudhari
fuente
32

Mira esto :

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

Si está usando fmdb , creo que puede importar FMDatabaseAdditions y usar la función bool:

[yourfmdbDatabase tableExists:tableName].
usuario655489
fuente
1
Asegúrese de importar "FMDatabaseAdditions.h" para usar este método o se preguntará por qué lo eliminaron. :)
Será el
Aunque esta podría ser una respuesta correcta, la pregunta era sobre sqlite, no una biblioteca en particular en un idioma en particular. Creo que la respuesta debería ser proporcionar código sql, no una llamada a uno de los métodos de la biblioteca
nacho4d
13

El siguiente código devuelve 1 si la tabla existe o 0 si la tabla no existe.

SELECT CASE WHEN tbl_name = "name" THEN 1 ELSE 0 END FROM sqlite_master WHERE tbl_name = "name" AND type = "table"
pacheco
fuente
1
Esto aún no devolverá nada si la tabla no existe, porque la condición where impide cualquier resultado.
David Gausmann el
10

Tenga en cuenta que para verificar si existe una tabla en la base de datos TEMP, debe usar en sqlite_temp_masterlugar de sqlite_master:

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

Aquí está la función que usé:

Dado un objeto SQLDatabase = db

public boolean exists(String table) {
    try {
         db.query("SELECT * FROM " + table);
         return true;
    } catch (SQLException e) {
         return false;
    }
}
DroidGrailer
fuente
1
Lamentablemente tuve que usar esto en mi aplicación de Android, ya que descubrí que los dispositivos Samsung no usan la estructura de tabla sqlite_master estándar con la que todos los demás están trabajando.
Anthony Chuinard
7

Usa este código:

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

Si el recuento de matriz devuelto es igual a 1, significa que la tabla existe. De lo contrario no existe.

asmad
fuente
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: Esto está funcionando ahora en mi Mac con Python 3.7.1

Douglas Goodall
fuente
Esto se ve más limpio que todas las otras respuestas ... ¡Gracias!
Harsha Vardhan
No funciona para mí: tengo que borrar los {} corchetes alrededor de table_name, entonces está bien.
Banana
1
Asegúrese de que table_nameno se proporcione desde una fuente no utilizada (como la entrada del usuario), de lo contrario será vulnerable a la inyección de SQL. Siempre es mejor usar parámetros en lugar de técnicas de manipulación de texto
astef
3

Utilizar

SELECT 1 FROM table LIMIT 1;

para evitar que se lean todos los registros.

Franz Fahrenkrog Petermann
fuente
Esto devuelve NULL si la tabla existe pero no tiene ningún registro.
radiospiel
Si la tabla no existe, arrojará un error. Captura eso, y sabes que no existe.
luckydonald 01 de
usar el manejo de errores como control de flujo generalmente no se considera la mejor práctica. Esto probablemente debería evitarse.
Jeff Woodard el
3

Puede escribir la siguiente consulta para verificar la existencia de la tabla.

SELECT name FROM sqlite_master WHERE name='table_name'

Aquí 'nombre_tabla' es el nombre de la tabla que creó. Por ejemplo

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

y verifica

  SELECT name FROM sqlite_master WHERE name='country'
akn
fuente
66
¿Cómo es esto diferente de la respuesta votada ya aceptada de hace 9 años?
Kevin Van Dyck
3

La forma más confiable que he encontrado en C # en este momento, usando el último paquete nuget sqlite-net-pcl (1.5.231) que está usando SQLite 3, es la siguiente:

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

Usar una simple consulta SELECT es, en mi opinión, bastante confiable. Sobre todo, puede verificar la existencia de tablas en muchos tipos de bases de datos diferentes (SQLite / MySQL).

SELECT 1 FROM table;

Tiene sentido cuando puede usar otro mecanismo confiable para determinar si la consulta tuvo éxito (por ejemplo, consulta una base de datos a través de QSqlQuery en Qt ).

Grz
fuente
1

La función c ++ comprueba db y todas las bases de datos adjuntas para ver si existen tablas y columnas (opcionalmente)

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

Editar: Recientemente descubrí la función sqlite3_table_column_metadata. Por lo tanto

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;}
No comprendo
fuente
tableExists booleanos estáticos públicos (base de datos SQLiteDatabase, String tableName) {return database.rawQuery ("SELECT name FROM sqlite_master WHERE type = 'table' AND name = '" + tableName + "'", null) .moveToFirst (); }
nick
De manera muy ineficiente y arriesgada, la concatenación de cadenas puede terminar en todo.
Andrea Moro
0

Este es mi código para 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");
    }
});

Y el otro:

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

Pensé que pondría mis 2 centavos en esta discusión, incluso si es bastante antigua. Esta consulta devuelve el escalar 1 si la tabla existe y 0 en caso contrario.

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

La tabla existe o no en la base de datos en 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
fuente