Como verificar se existe uma tabela em um banco de dados Android SQLite?

87

Tenho um aplicativo para Android que precisa verificar se já existe um registro no banco de dados e, se não houver, processar algumas coisas e, eventualmente, inseri-lo e simplesmente ler os dados do banco de dados se os dados existirem. Estou usando uma subclasse de SQLiteOpenHelper para criar e obter uma instância regravável de SQLiteDatabase, que pensei que automaticamente se encarregaria de criar a tabela se ela ainda não existisse (já que o código para fazer isso está no onCreate (... ) método).

No entanto, quando a tabela ainda NÃO existe e o primeiro método executado no objeto SQLiteDatabase que tenho é uma chamada para consulta (...), meu logcat mostra um erro de "I / Database (26434): sqlite retornado: erro code = 1, msg = no such table: appdata ", e com certeza, a tabela appdata não está sendo criada.

Alguma ideia do porquê?

Estou procurando um método para testar se a tabela existe (porque se não existir, os dados certamente não estarão nela, e eu não preciso ler até que eu escreva nela, o que parece criar a tabela corretamente), ou uma maneira de garantir que ele seja criado, e apenas vazio, a tempo para a primeira chamada de consulta (...)

EDITAR
Isso foi postado após as duas respostas abaixo:
Acho que posso ter encontrado o problema. Por algum motivo, decidi que um SQLiteOpenHelper diferente deveria ser criado para cada tabela, embora ambos acessem o mesmo arquivo de banco de dados. Acho que refatorar esse código para usar apenas um OpenHelper e criar as duas tabelas dentro do onCreate pode funcionar melhor ...

camperdave
fonte

Respostas:

127

Tente este:

public boolean isTableExists(String tableName, boolean openDb) {
    if(openDb) {
        if(mDatabase == null || !mDatabase.isOpen()) {
            mDatabase = getReadableDatabase();
        }

        if(!mDatabase.isReadOnly()) {
            mDatabase.close();
            mDatabase = getReadableDatabase();
        }
    }

    String query = "select DISTINCT tbl_name from sqlite_master where tbl_name = '"+tableName+"'";
    try (Cursor cursor = mDatabase.rawQuery(query, null)) {
        if(cursor!=null) {
            if(cursor.getCount()>0) {
                return true;
            }
        }
        return false;
    }
}
Nikolay DS
fonte
Muito obrigado por isso. Funciona bem. +1
Gray de
11
Não se esqueçacursor.close();
styler1972
1
Por motivo desconhecido, o nome da tabela diferencia maiúsculas de minúsculas. Eu prefiro usarselect * from sqlite_master where UPPER(name) = 'ROUTES'.
Thupten
4
Boa resposta, mas gramática dolorosa! Certamente deve ser chamado de 'isTableExisting ()'.
Chris Hatton
1
Isso funcionou para mim, mas eu tive que envolver a consulta em um try / catch ou meu aplicativo travaria quando a tabela não existisse.
Braden Holt
52

Não sei nada sobre a API Android SQLite, mas se você consegue falar com ela diretamente no SQL, pode fazer o seguinte:

create table if not exists mytable (col1 type, col2 type);

O que garantirá que a tabela seja sempre criada e não gerará nenhum erro se já existir.

Crisbtoo
fonte
É assim que estou criando a tabela no método onCreate dentro da classe SQLiteOpenHelper. No android, é recomendável deixar que essa classe crie a tabela, pois permite que o aplicativo atualize seu banco de dados automaticamente, e aparentemente é mais eficiente em geral. Infelizmente, aquele codeblock que executa código muito parecido com o que você escreveu não está sendo executado a tempo :(
camperdave
Isso funciona muito bem e também funciona com índices, ou seja: "criar índice se não existir [...]".
Eric Fortier
5
Esta é realmente a melhor resposta para a pergunta feita.
The Original Android
1
mas a pergunta não pede para criar um
10101010
12

Embora já existam muitas respostas boas para essa pergunta, eu encontrei outra solução que acho mais simples. Cerque sua consulta com um bloco try e a seguinte captura:

catch (SQLiteException e){
    if (e.getMessage().contains("no such table")){
            Log.e(TAG, "Creating table " + TABLE_NAME + "because it doesn't exist!" );
            // create table
            // re-run query, etc.
    }
}

Funcionou para mim!

roubo
fonte
1
Não seria melhor colocar a instrução Log dentro do bloco if ()? Parece que se a SQLiteException for lançada por outro motivo diferente de "nenhuma tabela", o log indicará que você está criando a tabela, mas na verdade não está.
2
Usar exceções para controlar o fluxo é algo para se envergonhar, não é ensinado a outras pessoas. Verificar a mensagem dessa forma, duplamente.
Nick Cardoso
Se usado com moderação, não acho que haja algo de errado em usar exceções em casos de uso como o descrito acima. Certamente nada de que me envergonhe.
robguinness
Acho que e.getMessage().contains("no such table")é pior do que usar exceções para o fluxo de controle. Ambos são estilos inadequados, mas analisar mensagens de erro para um texto específico é até mesmo um estilo muito ruim.
jox de
11

Isso é o que eu fiz:

/* open database, if doesn't exist, create it */
SQLiteDatabase mDatabase = openOrCreateDatabase("exampleDb.db", SQLiteDatabase.CREATE_IF_NECESSARY,null);

Cursor c = null;
boolean tableExists = false;
/* get cursor on it */
try
{
    c = mDatabase.query("tbl_example", null,
        null, null, null, null, null);
        tableExists = true;
}
catch (Exception e) {
    /* fail */
    Log.d(TAG, tblNameIn+" doesn't exist :(((");
}

return tableExists;
AndroidDebaser
fonte
8

Sim, a teoria da minha edição estava certa: o problema que estava fazendo com que o método onCreate não rodasse era o fato de que os SQLiteOpenHelperobjetos deveriam se referir a bancos de dados, e não ter um separado para cada tabela. Juntar as duas tabelas em uma só SQLiteOpenHelperresolveu o problema.

camperdave
fonte
2

Você mencionou que criou uma classe que estende SQLiteOpenHelpere implementa o onCreatemétodo. Você está certificando-se de que está executando todas as chamadas de aquisição de banco de dados com essa classe? Você só deve obter SQLiteDatabaseobjetos por meio do SQLiteOpenHelper#getWritableDatabasee, getReadableDatabasecaso contrário, o onCreatemétodo não será chamado quando necessário. Se você já está fazendo isso, verifique se o SQLiteOpenHelper#onUpgrademétodo está sendo chamado. Nesse caso, o número da versão do banco de dados foi alterado em algum momento, mas a tabela nunca foi criada corretamente quando isso aconteceu.

Como um aparte, você pode forçar a recriação do banco de dados, certificando-se de que todas as conexões com ele estejam fechadas e chamando Context#deleteDatabasee, em seguida, usando o SQLiteOpenHelperpara fornecer um novo objeto db.

Rich Schuler
fonte
Bem, estou obtendo meu objeto de banco de dados por meio da chamada getWritableDatabase (), desculpe, esqueci de especificar isso. Além disso, tenho certeza de que onUpgrade () não está sendo chamado, visto que esse método tem uma chamada Log.d (...) como sua primeira linha que não estou vendo no banco de dados. Vou tentar excluir todo o arquivo de banco de dados e ver se isso de alguma forma corrige isso ...
camperdave
Infelizmente, a exclusão de todo o banco de dados (usei o root explorer para limpar o arquivo) não funcionou. Eu uso duas tabelas em meu aplicativo - uma delas foi inicializada perfeitamente, mas a outra, que sempre me deu problemas, não.
camperdave de
2
 // @param db, readable database from SQLiteOpenHelper

 public boolean doesTableExist(SQLiteDatabase db, String tableName) {
        Cursor cursor = db.rawQuery("select DISTINCT tbl_name from sqlite_master where tbl_name = '" + tableName + "'", null);

    if (cursor != null) {
        if (cursor.getCount() > 0) {
            cursor.close();
            return true;
        }
        cursor.close();
    }
    return false;
}
  • sqlite mantém a tabela sqlite_master contendo informações de todas as tabelas e índices no banco de dados.
  • Portanto, aqui estamos simplesmente executando o comando SELECT nele, obteremos o cursor com contagem 1 se a tabela existir.
Akshansh Singh
fonte
0
 public boolean isTableExists(String tableName) {
    boolean isExist = false;
    Cursor cursor = db.rawQuery("select DISTINCT tbl_name from sqlite_master where tbl_name = '" + tableName + "'", null);
    if (cursor != null) {
        if (cursor.getCount() > 0) {
            isExist = true;
        }
        cursor.close();
    }
    return isExist;
}
Yogesh Rathi
fonte
0

no such table exists: error está chegando porque uma vez que você cria um banco de dados com uma tabela depois disso, sempre que você cria uma tabela no mesmo banco de dados dá esse erro.

Para resolver este erro você deve criar um novo banco de dados e dentro do método onCreate () você pode criar várias tabelas no mesmo banco de dados.

Megha
fonte
0

A condição importante é IF NOT EXISTS para verificar a tabela já existe ou não no banco de dados

gostar...

String query = "CREATE TABLE IF NOT EXISTS " + TABLE_PLAYER_PHOTO + "("
            + KEY_PLAYER_ID + " TEXT,"
            + KEY_PLAYER_IMAGE + " TEXT)";
db.execSQL(query);
Pankaj Talaviya
fonte
0

Enfrentei isso e lidei com isso tentando pegar tão simples quanto eu faço o que quero na tabela se não existir causará erro, então pegue pelas exceções e crie-o :)

SQLiteDatabase db=this.getWritableDatabase();
        try{
            db.execSQL("INSERT INTO o_vacations SELECT * FROM vacations");
            db.execSQL("DELETE FROM vacations");
        }catch (SQLiteException e){
            db.execSQL("create table o_vacations (id integer primary key ,name text ,vacation text,date text,MONTH text)");
            db.execSQL("INSERT INTO o_vacations SELECT * FROM vacations");
            db.execSQL("DELETE FROM vacations");
        }

Aly Abdelaal
fonte
-1

..... Toast t = Toast.makeText (context, "try ...", Toast.LENGTH_SHORT); t.show ();

    Cursor callInitCheck = db.rawQuery("select count(*) from call", null);

    Toast t2a = Toast.makeText(context, "count rows " + callInitCheck.getCount() , Toast.LENGTH_SHORT);
    t2a.show();

    callInitCheck.moveToNext();
    if( Integer.parseInt( callInitCheck.getString(0)) == 0) // if no rows then do
    {
        // if empty then insert into call

.....

Srinath Ganesh
fonte