Como verifico no SQLite se existe uma tabela?

895

Como, de forma confiável , verifico no SQLite se existe uma tabela de usuário específica?

Não estou pedindo formas não confiáveis, como verificar se um "select *" na tabela retornou um erro ou não (isso é uma boa idéia?).

O motivo é o seguinte:

No meu programa, preciso criar e preencher algumas tabelas se elas ainda não existirem.

Se eles já existirem, preciso atualizar algumas tabelas.

Em vez disso, devo seguir outro caminho para sinalizar que as tabelas em questão já foram criadas - por exemplo, criando / colocando / definindo um determinado sinalizador no meu arquivo de inicialização / configurações do programa no disco ou algo assim?

Ou minha abordagem faz sentido?

PoorLuzer
fonte
O SQLite lançará uma exceção se a tabela em um select não existir. Simplesmente não há necessidade de nenhum trabalho mais sofisticado.
NoChance
34
@NoChance, mas também haverá várias outras coisas. É um pouco como ver se essa árvore está realmente lá, dirigindo para a frente com os olhos fechados, você descobrirá de uma maneira ou de outra :) #
395
@randomsock, bom exemplo, mas um pouco assustador, especialmente se o carro fosse meu carro ...
NoChance
@ Randomsock, não sei qual é a convenção sqlite, mas é mais pitônico pedir perdão do que permissão. ou seja, pegue a exceção em vez de usar uma condicional.
Eric
1
@Eric A partir de agora, a questão não envolve Python, mas, assumindo que o erro é genérico sqlite3.OperationalError, você deve analisar a mensagem de erro para garantir que seja, por exemplo, a mensagem "table TABLE_NAME já existe" ao criar uma tabela e, se não, reraise o erro e acho que não há garantia de que o fraseado do erro não seja alterado.
Markus von Broady

Respostas:

1023

Perdi a entrada da FAQ.

De qualquer forma, para referência futura, a consulta completa é:

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

Onde {table_name}é o nome da tabela para verificar.

Seção de documentação para referência: Formato de arquivo do banco de dados. 2.6 Armazenamento do esquema do banco de dados SQL

  • Isso retornará uma lista de tabelas com o nome especificado; isto é, o cursor terá uma contagem de 0 (não existe) ou uma contagem de 1 (existe)
PoorLuzer
fonte
7
Qual documentação da SQLite cobre essas tabelas do sistema?
Pawel Veselov
29
@Pawel Veselov: A seção intitulada "File Format para SQLite Databases": sqlite.org/fileformat2.html
Bryan Oakley
14
Isso não funcionará para tabelas TEMP, no entanto. As tabelas TEMP estão em "sqlite_temp_master".
PatchyFog
11
Isso retorna um valor booleano? O que ele retorna se a tabela existir ou não?
Dagrooms
8
@Dagrooms Isso retornará uma lista de tabelas com o nome especificado; isto é, o cursor terá uma contagem de 0 (não existe) ou uma contagem de 1 (existe).
Rein S
555

Se você estiver usando o SQLite versão 3.3 ou superior, poderá criar facilmente uma tabela com:

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

Da mesma maneira, você pode remover uma tabela apenas se ela existir, usando:

drop table if exists TableName
Arthur Johnson
fonte
3
Observe que a create tableinstrução está incompleta (faltando a especificação das colunas da tabela).
Eric Platon
11
há também construo semelhante para os índices: criar índice se não existe TableName_col1 em NomeTabela (COL1)
lowtech
26
Esta não deve ser a resposta aceita, mas seria se a pergunta tivesse uma redação diferente. O OP não perguntou como verificar uma tabela antes de soltar ou criar. E se você precisar consultar uma tabela que possivelmente não existe? Esse é o problema que estou enfrentando agora, e a resposta aceita funciona melhor nesta declaração geral de problemas. Esta é uma boa alternativa rápida.
Dagrooms
@ Dagrooms, você pode estar certo. Embora o OP não tenha perguntado isso, eu estava procurando por esta resposta :)
earik87
169

Uma variação seria usar SELECT COUNT (*) em vez de SELECT NAME, ou seja,

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

Isso retornará 0, se a tabela não existir, 1 se existir. Isso provavelmente é útil em sua programação, pois um resultado numérico é mais rápido / fácil de processar. A seguir, ilustra como você faria isso no Android usando SQLiteDatabase, Cursor, rawQuery com 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
fonte
33
Eu acredito que um "SELECT 1" seria ainda mais rápido.
PatchyFog
Por que cursor.getInt (0) é igual à contagem de registros no banco de dados?
Semyon Danilov 23/01
1
Contamos o número de vezes que TABLE aparece no esquema sqlite. Uma contagem de 0 significa que a tabela não existe. Uma contagem de 1 significa que a tabela existe. Estes são os únicos dois valores esperados de contagem.
Stephen Quan
1
Embora o número (de COUNT(*)) seja fácil de processar, é ainda mais fácil retornar a existência de uma linha ou não; se houver uma linha lá, ela existe; se não houver uma linha, não existe. (Você já verificar se há falha na moveToFirst, de modo que o trabalho seria feito nesse ponto.)
traço-tom-bang
Atualize seu código para fechar o cursor antes de retornar falso.
Dave Thomas
43

Você poderia tentar:

SELECT name FROM sqlite_master WHERE name='table_name'
Galego
fonte
4
type = table seria útil tho
mafu 30/03/12
Se estiver usando C #, não use este comando em a SQLiteReader reader = cmd.ExecuteReader();e faça a dt.Load(reader)(onde dtestá a DataTable). Eu achei que dá essa Object reference is not an instance of an objectexceção no .Load()se a tabela não for encontrada. Em vez disso, use ae SQLiteDataAdapter adapter = new SQLiteDataAdapter(cmd); do adapter.Fill(ds), onde dsé a DataSet. Você pode ver se ds.Tables.Count > 0e return ds.Tables[0];se sim (ou else return null). Em seguida, você pode verificar que DataTablepor ser null, se dt.Rows != null, e sedt.Rows.Count>0
vapcguy
34

Usar:

PRAGMA table_info(your_table_name)

Se a tabela resultante estiver vazia, your_table_nameela não existe.

Documentação:

Schema.table_info PRAGMA (nome da tabela);

Esse pragma retorna uma linha para cada coluna na tabela nomeada. As colunas no conjunto de resultados incluem o nome da coluna, o tipo de dados, se a coluna pode ou não ser NULL e o valor padrão para a coluna. A coluna "pk" no conjunto de resultados é zero para colunas que não fazem parte da chave primária e é o índice da coluna na chave primária para colunas que fazem parte da chave primária.

A tabela nomeada no pragma table_info também pode ser uma visualização.

Exemplo de saída:

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
fonte
Essa é uma ótima maneira de determinar se existe uma tabela no Python.
Michael Murphy
ou Xamarin Forms
SerenityNow
4
Esta é uma ótima maneira de obter as definições de coluna programaticamente
w00t
33

Os nomes de tabela SQLite não diferenciam maiúsculas de minúsculas, mas a comparação diferencia maiúsculas de minúsculas por padrão. Para fazer isso funcionar corretamente em todos os casos, você precisa adicionar COLLATE NOCASE.

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

Se você estiver recebendo um erro "a tabela já existe", faça as alterações na string SQL, conforme abaixo:

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

Dessa forma, você pode evitar as exceções.

Rakesh Chaudhari
fonte
32

Veja isto :

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

Se você estiver usando o fmdb , acho que você pode importar o FMDatabaseAdditions e usar a função bool:

[yourfmdbDatabase tableExists:tableName].
user655489
fonte
1
Certifique-se de importar "FMDatabaseAdditions.h" para usar este método, ou então você se perguntará por que eles o removeram! :)
Will
Embora essa possa ser uma resposta correta, a pergunta era sobre o sqlite e não uma biblioteca específica em um idioma específico. Acho que a resposta deve ser o de fornecer o código SQL, não uma chamada para um dos métodos da biblioteca
nacho4d
13

O código a seguir retorna 1 se a tabela existir ou 0 se a tabela não existir.

SELECT CASE WHEN tbl_name = "name" THEN 1 ELSE 0 END FROM sqlite_master WHERE tbl_name = "name" AND type = "table"
pacheco
fonte
1
Isso ainda não retornará nada se a tabela não existir, porque a condição where impede qualquer resultado.
David Gausmann
10

Observe que, para verificar se existe uma tabela no banco de dados TEMP, você deve usar em sqlite_temp_mastervez de sqlite_master:

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

Aqui está a função que eu usei:

Dado um objeto SQLDatabase = db

public boolean exists(String table) {
    try {
         db.query("SELECT * FROM " + table);
         return true;
    } catch (SQLException e) {
         return false;
    }
}
DroidGrailer
fonte
1
Infelizmente, eu tive que usar isso no meu aplicativo Android, pois descobri que os dispositivos Samsung não usam a estrutura de tabela sqlite_master padrão com a qual todos os outros estão trabalhando.
Anthony Chuinard
7

Use este código:

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

Se a contagem de matriz retornada for igual a 1, significa que a tabela existe. Caso contrário, não existe.

asmad
fonte
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: Isso está funcionando agora no meu Mac com o Python 3.7.1

Douglas Goodall
fonte
Parece mais limpo do que todas as outras respostas .. Obrigado !!
Harsha Vardhan
Não funciona para mim: tem que apagar os colchetes {} em torno de table_name, então tudo bem.
Banana
1
Certifique-se de que table_namenão seja fornecido de origem não tratada (como entrada do usuário), caso contrário, estará vulnerável à injeção de SQL. É sempre melhor usar parâmetros, em vez de técnicas de manipulação de texto,
astef
3

Usar

SELECT 1 FROM table LIMIT 1;

para impedir que todos os registros sejam lidos.

Franz Fahrenkrog Petermann
fonte
Isso retorna NULL se a tabela existir, mas não tiver nenhum registro.
Radiospiel
Se a tabela não existir, ocorrerá um erro. Veja isso e você sabe que não existe.
Luckydonald
usar o tratamento de erros como controle de fluxo geralmente não é considerado uma prática recomendada. Provavelmente isso deve ser evitado.
Jeff Woodard
3

Você pode escrever a seguinte consulta para verificar a existência da tabela.

SELECT name FROM sqlite_master WHERE name='table_name'

Aqui 'table_name' é o nome da sua tabela que você criou. Por exemplo

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

e verifique

  SELECT name FROM sqlite_master WHERE name='country'
akn
fonte
6
Como isso é diferente da resposta já votada já aceita há 9 anos?
Kevin Van Dyck
3

A maneira mais confiável que encontrei no C # agora, usando o pacote mais recente do sqlite-net-pcl nuget (1.5.231) que usa o SQLite 3, é o seguinte:

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

Usar uma consulta SELECT simples é - na minha opinião - bastante confiável. Acima de tudo, ele pode verificar a existência da tabela em muitos tipos diferentes de banco de dados (SQLite / MySQL).

SELECT 1 FROM table;

Faz sentido quando você pode usar outro mecanismo confiável para determinar se a consulta foi bem-sucedida (por exemplo, você consulta um banco de dados via QSqlQuery no Qt ).

Grz
fonte
1

A função c ++ verifica o banco de dados e todos os bancos de dados anexados quanto à existência de tabela e (opcionalmente) coluna.

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

Edit: Descoberto recentemente a função sqlite3_table_column_metadata. Conseqüentemente

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;}
Não compreende
fonte
tableExists público booleano estático (banco de dados SQLiteDatabase, String tableName) {return database.rawQuery ("SELECT name FROM sqlite_master WHERE type = 'table' AND name = '" + tableName + "'", null) .moveToFirst (); }
nick
Maneira muito ineficiente e arriscada, pois a concatenação de strings pode acabar em tudo.
Andrea Moro
0

Este é o meu 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");
    }
});

E o outro:

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

Eu pensei em colocar meus 2 centavos nessa discussão, mesmo que seja um pouco antigo. Essa consulta retorna o escalar 1 se a tabela existir e 0 caso contrário.

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

A tabela existe ou não no banco de dados no 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
fonte