Jak sprawdzić, czy tabela istnieje w bazie danych SQLite systemu Android?

87

Mam aplikację na Androida, która musi sprawdzić, czy istnieje już rekord w bazie danych, a jeśli nie, przetworzyć niektóre rzeczy i ostatecznie je wstawić i po prostu odczytać dane z bazy danych, jeśli dane istnieją. Używam podklasy SQLiteOpenHelper do tworzenia i uzyskiwania instancji SQLiteDatabase z możliwością wielokrotnego zapisu, która według mnie automatycznie zajęła się utworzeniem tabeli, jeśli jeszcze nie istnieje (ponieważ kod do tego znajduje się w onCreate (... ) metoda).

Jednak gdy tabela jeszcze NIE istnieje, a pierwsza metoda uruchomiona na obiekcie SQLiteDatabase, którą mam, to wywołanie zapytania (...), mój logcat pokazuje błąd „I / Database (26434): sqlite zwrócił: błąd code = 1, msg = no such table: appdata "i oczywiście, tabela appdata nie jest tworzona.

Jakieś pomysły, dlaczego?

Szukam jednej z metod, aby sprawdzić, czy tabela istnieje (ponieważ jeśli nie, to danych na pewno nie ma w niej) i nie muszę jej czytać, dopóki do niej nie napiszę, co wydaje się tworzyć tabelę poprawnie) lub sposób, aby upewnić się, że zostanie utworzony i jest po prostu pusty, na czas pierwszego wywołania zapytania (...)

EDYCJA
Zostało to wysłane po dwóch odpowiedziach poniżej:
Myślę, że mogłem znaleźć problem. Z jakiegoś powodu zdecydowałem, że dla każdej tabeli powinien zostać utworzony inny SQLiteOpenHelper, mimo że oba mają dostęp do tego samego pliku bazy danych. Myślę, że refaktoryzacja tego kodu, aby używał tylko jednego OpenHelpera i tworzenie obu tabel w jego onCreate może działać lepiej ...

camperdave
źródło

Odpowiedzi:

127

Spróbuj tego:

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
źródło
Wielkie dzięki za to. Działa świetnie. +1
Gray
11
Nie zapomnijcursor.close();
styler1972
1
Z nieznanego powodu w nazwie tabeli rozróżniana jest wielkość liter. Raczej używamselect * from sqlite_master where UPPER(name) = 'ROUTES'.
Thupten
4
Dobra odpowiedź, ale bolesna gramatyka! Z pewnością powinien nazywać się „isTableExisting ()”.
Chris Hatton
1
To zadziałało dla mnie, ale musiałem zawinąć zapytanie w try / catch lub moja aplikacja uległa awarii, gdy tabela nie istniała.
Braden Holt
52

Nie wiem nic o Android SQLite API, ale jeśli potrafisz rozmawiać z nim bezpośrednio w SQL, możesz to zrobić:

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

Co zapewni, że tabela będzie zawsze tworzona i nie będzie zgłaszać żadnych błędów, jeśli już istniała.

chrisbtoo
źródło
Tak właśnie tworzę tabelę w metodzie onCreate wewnątrz klasy SQLiteOpenHelper. W systemie Android zaleca się, aby ta klasa utworzyła tabelę, ponieważ pozwala aplikacji na automatyczną aktualizację bazy danych i ogólnie jest najwyraźniej bardziej wydajna. Niestety, ten blok kodu, który wykonuje kod podobny do tego, który napisałeś, nie działa na czas :(
camperdave
Działa to świetnie i działa również z indeksami, np .: "utwórz indeks, jeśli nie istnieje [...]".
Eric Fortier
5
To właściwie najlepsza odpowiedź na zadane pytanie.
The Original Android
1
ale pytanie nie wymaga utworzenia jednego
10101010
12

Chociaż jest już wiele dobrych odpowiedzi na to pytanie, wymyśliłem inne rozwiązanie, które moim zdaniem jest prostsze. Otocz zapytanie blokiem try i następującym haczykiem:

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

U mnie zadziałało!

robguinness
źródło
1
Czy nie byłoby lepiej umieścić instrukcję Log wewnątrz bloku if ()? Wygląda na to, że jeśli wyjątek SQLiteException zostanie zgłoszony z innego powodu niż „brak takiej tabeli”, dziennik wskaże, że tworzysz tabelę, podczas gdy w rzeczywistości tak nie jest.
2
Używanie wyjątków do kontrolowania przepływu jest czymś, czego należy się wstydzić, czego nie należy uczyć innych. Podwójne sprawdzenie wiadomości w ten sposób.
Nick Cardoso,
Jeśli jest używany oszczędnie, nie sądzę, aby było coś złego w używaniu wyjątków w przypadkach użycia, takich jak opisany powyżej. Z pewnością nic mi się nie wstydzi.
robguinness
Myślę, że e.getMessage().contains("no such table")jest to gorsze niż używanie wyjątków dla przepływu kontroli. Oba są w złym stylu, ale analizowanie komunikatów o błędach dla określonego tekstu jest nawet w bardzo złym stylu.
jox
11

Oto co zrobiłem:

/* 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
źródło
8

Tak, okazuje się, że teoria w mojej edycji była słuszna: problemem, który powodował, że metoda onCreate nie działała, był fakt, że SQLiteOpenHelperobiekty powinny odwoływać się do baz danych, a nie mieć osobnej tabeli dla każdej tabeli. Spakowanie obu stołów w jeden SQLiteOpenHelperrozwiązało problem.

camperdave
źródło
2

Wspomniałeś, że utworzyłeś klasę, która rozszerza SQLiteOpenHelperi zaimplementowała onCreatemetodę. Czy upewniasz się, że wykonujesz wszystkie wywołania w bazie danych z tą klasą? Państwo powinno być tylko coraz SQLiteDatabaseprzedmiotów za pośrednictwem SQLiteOpenHelper#getWritableDatabasea getReadableDatabaseinaczej onCreatemetoda nie zostanie wywołana, gdy jest to konieczne. Jeśli już to robisz, sprawdź i zobacz, czy thSQLiteOpenHelper#onUpgrade zamiast tego wywoływana jest metoda. Jeśli tak, to numer wersji bazy danych został w pewnym momencie zmieniony, ale tabela nigdy nie została utworzona poprawnie, kiedy to się stało.

Nawiasem mówiąc, możesz wymusić odtworzenie bazy danych, upewniając się, że wszystkie połączenia z nią są zamknięte i wywołując, Context#deleteDatabasea następnie używając, SQLiteOpenHelperaby uzyskać nowy obiekt db.

Rich Schuler
źródło
Cóż, otrzymuję obiekt bazy danych przez wywołanie getWritableDatabase (), przepraszam, że zapomniałem o tym określić. Jestem również pewien, że onUpgrade () nie jest wywoływany, ponieważ ta metoda ma wywołanie Log.d (...) jako pierwszą linię, której nie widzę w bazie danych. Spróbuję usunąć cały plik bazy danych i zobaczymy, czy to jakoś to naprawi ...
camperdave
Niestety, usunięcie całej bazy danych (do wyczyszczenia pliku użyłem programu root Explorer) nie zadziałało. Używam dwóch tabel w mojej aplikacji - jedna z nich została zainicjowana idealnie, ale druga sprawiała mi kłopoty od początku.
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 utrzymuje tabelę sqlite_master zawierającą informacje o wszystkich tabelach i indeksach w bazie danych.
  • Więc tutaj po prostu uruchamiamy polecenie SELECT, otrzymamy kursor liczący 1, jeśli tabela istnieje.
Akshansh singh
źródło
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
źródło
0

no such table exists: error nadchodzi, ponieważ po utworzeniu bazy danych z jedną tabelą za każdym razem, gdy tworzysz tabelę w tej samej bazie danych, pojawia się ten błąd.

Aby rozwiązać ten błąd, musisz utworzyć nową bazę danych, a wewnątrz metody onCreate () możesz utworzyć wiele tabel w tej samej bazie danych.

Megha
źródło
0

Ważnym warunkiem jest JEŻELI NIE ISTNIEJE aby sprawdzić, czy tabela już istnieje w bazie danych lub jej nie ma

lubić...

String query = "CREATE TABLE IF NOT EXISTS " + TABLE_PLAYER_PHOTO + "("
            + KEY_PLAYER_ID + " TEXT,"
            + KEY_PLAYER_IMAGE + " TEXT)";
db.execSQL(query);
Pankaj Talaviya
źródło
0

napotkałem to i poradziłem sobie z tym, próbując złapać tak proste, jak to, robię to, co chcę w tabeli, jeśli nie istnieje, spowoduje błąd, więc złap go przez wyjątki i utwórz :)

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
źródło
-1

..... Toast t = Toast.makeText (kontekst, "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
źródło