Come si controlla se una tabella esiste in un database SQLite di Android?


87

Ho un'app Android che deve controllare se c'è già un record nel database e, in caso contrario, elaborare alcune cose ed eventualmente inserirle e semplicemente leggere i dati dal database se i dati esistono. Sto usando una sottoclasse di SQLiteOpenHelper per creare e ottenere un'istanza riscrivibile di SQLiteDatabase, che pensavo si occupasse automaticamente di creare la tabella se non esisteva già (poiché il codice per farlo è in onCreate (... ) metodo).

Tuttavia, quando la tabella NON esiste ancora e il primo metodo eseguito sull'oggetto SQLiteDatabase che ho è una chiamata a query (...), il mio logcat mostra un errore di "I / Database (26434): sqlite restituito: errore code = 1, msg = no such table: appdata "e, abbastanza sicuro, la tabella appdata non viene creata.

Qualche idea sul perché?

Sto cercando un metodo per verificare se la tabella esiste (perché se non lo è, i dati non sono certamente in essa, e non ho bisogno di leggerli finché non ci scrivo, il che sembra creare la tabella correttamente), o un modo per assicurarsi che venga creato, ed è solo vuoto, in tempo per la prima chiamata per interrogare (...)

EDIT
Questo è stato pubblicato dopo le due risposte seguenti:
Penso di aver trovato il problema. Per qualche motivo ho deciso che doveva essere creato un diverso SQLiteOpenHelper per ogni tabella, anche se entrambi accedono allo stesso file di database. Penso che il refactoring di quel codice per utilizzare un solo OpenHelper e la creazione di entrambe le tabelle all'interno di onCreate potrebbe funzionare meglio ...

Risposte:


127

Prova questo:

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

Grazie mille per questo. Funziona alla grande. +1
Gray

11
Non dimenticarecursor.close();
styler1972

1
Per motivi sconosciuti, il tablename è sensibile al maiuscolo / minuscolo. Preferisco usareselect * from sqlite_master where UPPER(name) = 'ROUTES'.
Thupten

4
Bella risposta ma grammatica dolorosa! Dovrebbe sicuramente essere chiamato 'isTableExisting ()'.
Chris Hatton

1
Questo ha funzionato per me, ma ho dovuto racchiudere la query in un tentativo / cattura o la mia app si sarebbe bloccata quando la tabella non esisteva.
Braden Holt

52

Non so nulla dell'API SQLite di Android, ma se riesci a parlarle direttamente in SQL, puoi farlo:

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

Ciò garantirà che la tabella venga sempre creata e non genererà errori se già esisteva.


È così che creo la tabella nel metodo onCreate all'interno della classe SQLiteOpenHelper. In Android, si consiglia di consentire a quella classe di creare la tabella, poiché consente all'app di aggiornare automaticamente il database ed è apparentemente più efficiente in generale. Sfortunatamente, quel blocco di codici che esegue codice simile a quello che hai scritto non viene eseguito in tempo :(
camperdave

Funziona alla grande e funziona anche con gli indici, ad esempio: "crea un indice se non esiste [...]".
Eric Fortier

5
Questa è in realtà la migliore risposta alla domanda posta.
L'originale Android

1
ma la domanda non chiede di crearne uno
10101010

12

Sebbene ci siano già molte buone risposte a questa domanda, ho trovato un'altra soluzione che penso sia più semplice. Circonda la tua query con un blocco try e la seguente cattura:

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

Ha funzionato per me!


1
Non sarebbe meglio mettere l'istruzione Log all'interno del blocco if ()? Sembra che se SQLiteException viene lanciata per un motivo diverso da "nessuna tabella di questo tipo", il log indicherà che stai creando la tabella, mentre in realtà non lo sei.

2
Usare le eccezioni per controllare il flusso è qualcosa di cui vergognarsi, non insegnato agli altri. Controllare il messaggio in quel modo, doppiamente.
Nick Cardoso

Se usato con parsimonia, non credo ci sia nulla di sbagliato nell'usare le eccezioni in casi d'uso come quello descritto sopra. Certamente niente di cui mi vergogno.
robguinness

Penso che e.getMessage().contains("no such table")sia peggio che usare le eccezioni per il flusso di controllo. Entrambi sono di cattivo stile, ma analizzare i messaggi di errore per un testo specifico è anche uno stile molto cattivo.
jox

11

Questo è quello che ho fatto:

/* 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;

8

Sì, risulta che la teoria nella mia modifica era giusta: il problema che causava la mancata esecuzione del metodo onCreate era il fatto che gli SQLiteOpenHelperoggetti dovevano fare riferimento a database e non averne uno separato per ogni tabella. Comprimere entrambe le tabelle in una ha SQLiteOpenHelperrisolto il problema.


2

Hai detto di aver creato una classe che estende SQLiteOpenHelpere implementa il onCreatemetodo. Ti stai assicurando di eseguire tutte le chiamate di acquisizione del database con quella classe? Si dovrebbe essere sempre solo SQLiteDatabasegli oggetti tramite l' SQLiteOpenHelper#getWritableDatabasee getReadableDatabasealtrimenti il onCreatemetodo non verrà chiamato quando necessario. Se lo stai già facendo, controlla e vedi se SQLiteOpenHelper#onUpgradeinvece viene chiamato il metodo. In tal caso, il numero di versione del database è stato modificato a un certo punto nel tempo, ma la tabella non è mai stata creata correttamente quando è successo.

Per inciso, puoi forzare la ricreazione del database assicurandoti che tutte le connessioni ad esso siano chiuse e chiamando Context#deleteDatabasee quindi usando il SQLiteOpenHelperper darti un nuovo oggetto db.


Bene, sto ottenendo il mio oggetto database tramite la chiamata getWritableDatabase (), scusa se mi sono dimenticato di specificarlo. Inoltre, sono sicuro che onUpgrade () non viene chiamato, poiché quel metodo ha una chiamata Log.d (...) come prima riga che non vedo nel database. Proverò a eliminare l'intero file di database e vedremo se in qualche modo lo risolve ...
camperdave

Sfortunatamente, l'eliminazione dell'intero database (ho usato root explorer per eliminare il file) non ha funzionato. Uso due tabelle nella mia app: una è stata inizializzata perfettamente, ma l'altra che mi ha dato problemi non lo ha fatto.
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 mantiene la tabella sqlite_master contenente le informazioni di tutte le tabelle e gli indici nel database.
  • Quindi qui stiamo semplicemente eseguendo il comando SELEZIONA su di esso, otterremo il cursore con conteggio 1 se la tabella esiste.

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

0

no such table exists: error sta arrivando perché una volta che crei un database con una tabella, ogni volta che crei una tabella nello stesso database dà questo errore.

Per risolvere questo errore è necessario creare un nuovo database e all'interno del metodo onCreate () è possibile creare più tabelle nello stesso database.


0

Condizione importante è SE NON ESISTE per verificare che la tabella sia già esistente o meno nel database

piace...

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

0

L'ho affrontato e risolverlo provando a catturare il modo più semplice che faccio quello che voglio nella tabella se non esiste causerà un errore, quindi prendilo per eccezioni e crealo :)

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


-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

.....

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.