Comment vérifier si une table existe dans une base de données Android SQLite?

87

J'ai une application Android qui doit vérifier s'il y a déjà un enregistrement dans la base de données, et sinon, traiter certaines choses et finalement l'insérer, et simplement lire les données de la base de données si les données existent. J'utilise une sous-classe de SQLiteOpenHelper pour créer et obtenir une instance réinscriptible de SQLiteDatabase, qui, je pensais, s'occupait automatiquement de créer la table si elle n'existait pas déjà (puisque le code pour le faire est dans le onCreate (... ) méthode).

Cependant, lorsque la table n'existe PAS encore et que la première méthode exécutée sur l'objet SQLiteDatabase que j'ai est un appel à la requête (...), mon logcat affiche une erreur de "I / Database (26434): sqlite a retourné: erreur code = 1, msg = aucune table de ce type: appdata ", et bien sûr, la table appdata n'est pas en cours de création.

Des idées sur pourquoi?

Je recherche soit une méthode pour tester si la table existe (car si ce n'est pas le cas, les données ne sont certainement pas dedans, et je n'ai pas besoin de la lire avant d'y écrire, ce qui semble créer la table correctement), ou un moyen de s'assurer qu'il est créé, et est juste vide, à temps pour ce premier appel à la requête (...)

EDIT
Cela a été posté après les deux réponses ci-dessous:
Je pense que j'ai peut-être trouvé le problème. Pour une raison quelconque, j'ai décidé qu'un SQLiteOpenHelper différent était censé être créé pour chaque table, même si les deux accèdent au même fichier de base de données. Je pense que refactoriser ce code pour n'utiliser qu'un seul OpenHelper, et créer les deux tables à l'intérieur de onCreate peut fonctionner mieux ...

camperdave
la source

Réponses:

127

Essaye celui-là:

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
la source
Merci beaucoup pour ça. Fonctionne très bien. +1
Gray
11
N'oubliez pascursor.close();
styler1972
1
Pour une raison inconnue, le nom de la table est sensible à la casse. Je préfère utiliserselect * from sqlite_master where UPPER(name) = 'ROUTES'.
Jeudi
4
Belle réponse mais grammaire douloureuse! Devrait sûrement être appelé 'isTableExisting ()'.
Chris Hatton
1
Cela a fonctionné pour moi, mais j'ai dû envelopper la requête dans un try / catch ou mon application se plantait lorsque la table n'existait pas.
Braden Holt
52

Je ne sais rien de l'API Android SQLite, mais si vous pouvez lui parler directement en SQL, vous pouvez le faire:

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

Ce qui garantira que la table est toujours créée et ne lèvera aucune erreur si elle existait déjà.

chrisbtoo
la source
C'est ainsi que je crée la table dans la méthode onCreate à l'intérieur de la classe SQLiteOpenHelper. Sous Android, il est recommandé de laisser cette classe créer la table, car elle permet à l'application de mettre à jour automatiquement sa base de données et est apparemment plus efficace en général. Malheureusement, ce bloc de code qui exécute du code un peu comme celui que vous avez écrit n'est pas exécuté à temps :(
camperdave
Cela fonctionne très bien et fonctionne également avec les index, c'est-à-dire: "créer un index s'il n'existe pas [...]".
Eric Fortier
5
C'est en fait la meilleure réponse à la question posée.
L'Android d'origine
1
mais la question ne demande pas d'en créer un
10101010
12

Bien qu'il y ait déjà beaucoup de bonnes réponses à cette question, j'ai trouvé une autre solution que je trouve plus simple. Entourez votre requête d'un bloc try et de la capture suivante:

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

Cela a fonctionné pour moi!

robguinness
la source
1
Ne serait-il pas préférable de placer l'instruction Log dans le bloc if ()? Il semble que si l'exception SQLiteException est lancée pour une autre raison que "no such table", le journal indiquera que vous créez la table, alors que ce n'est pas le cas.
2
Utiliser des exceptions pour contrôler le flux est quelque chose dont il faut avoir honte, pas enseigné aux autres. Vérifier le message de cette manière, doublement.
Nick Cardoso
Si utilisé avec parcimonie, je ne pense pas qu'il y ait quelque chose de mal à utiliser des exceptions dans des cas d'utilisation tels que celui décrit ci-dessus. Certainement rien dont j'ai honte.
robguinness
Je pense que e.getMessage().contains("no such table")c'est pire que d'utiliser des exceptions pour contrôler le flux. Les deux sont de mauvais style, mais l'analyse des messages d'erreur pour un texte spécifique est même un très mauvais style.
jox
11

C'est ce que j'ai fait:

/* 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
la source
8

Oui, il s'avère que la théorie de ma modification était juste: le problème qui empêchait l'exécution de la méthode onCreate était le fait que les SQLiteOpenHelperobjets devaient faire référence à des bases de données et ne pas en avoir une séparée pour chaque table. Le regroupement des deux tables en une seule a SQLiteOpenHelperrésolu le problème.

camperdave
la source
2

Vous avez mentionné que vous avez créé une classe qui étend SQLiteOpenHelperet implémente la onCreateméthode. Assurez-vous que vous effectuez tous vos appels d'acquisition de base de données avec cette classe? Vous ne devriez obtenir des SQLiteDatabaseobjets que via le SQLiteOpenHelper#getWritableDatabase, getReadableDatabasesinon la onCreateméthode ne sera pas appelée si nécessaire. Si vous faites déjà cela, vérifiez et voyez si la SQLiteOpenHelper#onUpgrademéthode est appelée à la place. Si tel est le cas, le numéro de version de la base de données a été modifié à un moment donné, mais la table n'a jamais été créée correctement lorsque cela s'est produit.

En passant, vous pouvez forcer la recréation de la base de données en vous assurant que toutes les connexions sont fermées et en appelant Context#deleteDatabase, puis en utilisant le SQLiteOpenHelperpour vous donner un nouvel objet db.

Rich Schuler
la source
Eh bien, je reçois mon objet de base de données via l'appel getWritableDatabase (), désolé j'ai oublié de le spécifier. De plus, je suis sûr que onUpgrade () n'est pas appelé, car cette méthode a un appel Log.d (...) comme première ligne que je ne vois pas dans la base de données. Je vais essayer de supprimer tout le fichier de base de données, et nous verrons si cela résout le problème ...
camperdave
Malheureusement, la suppression de toute la base de données (j'ai utilisé l'explorateur racine pour purger le fichier) n'a pas fonctionné. J'utilise deux tables dans mon application - l'une d'elles parfaitement initialisée, mais l'autre qui me pose des problèmes depuis le début ne l'a pas fait.
camperdave
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 gère la table sqlite_master contenant les informations de toutes les tables et index de la base de données.
  • Donc, ici, nous exécutons simplement la commande SELECT dessus, nous obtiendrons un curseur ayant le compte 1 si la table existe.
Akshansh singh
la source
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
la source
0

no such table exists: error arrive car une fois que vous créez une base de données avec une table après cela, chaque fois que vous créez une table dans la même base de données, cette erreur s'affiche.

Pour résoudre cette erreur, vous devez créer une nouvelle base de données et dans la méthode onCreate (), vous pouvez créer plusieurs tables dans la même base de données.

Megha
la source
0

La condition importante est IF NOT EXISTS pour vérifier que la table existe déjà ou pas dans la base de données

comme...

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

J'ai fait face à cela et le gérer en essayant de capturer aussi simple que cela je fais ce que je veux dans la table s'il n'existe pas, cela causera une erreur, alors attrapez-le par exceptions et créez-le :)

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
la source
-1

..... Toast t = Toast.makeText (contexte, "essayez ...", 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
la source