จะตรวจสอบได้อย่างไรว่ามีตารางอยู่ในฐานข้อมูล Android SQLite หรือไม่?


87

ฉันมีแอป Android ที่ต้องการตรวจสอบว่ามีบันทึกอยู่ในฐานข้อมูลหรือไม่และหากไม่มีให้ประมวลผลบางอย่างและแทรกลงในที่สุดและอ่านข้อมูลจากฐานข้อมูลหากมีข้อมูลอยู่ ฉันใช้คลาสย่อยของ SQLiteOpenHelper เพื่อสร้างและรับอินสแตนซ์ SQLiteDatabase แบบเขียนซ้ำได้ซึ่งฉันคิดว่าจะดูแลการสร้างตารางโดยอัตโนมัติหากยังไม่มีอยู่ (เนื่องจากโค้ดที่ต้องทำนั้นอยู่ใน onCreate (... ) วิธี).

อย่างไรก็ตามเมื่อยังไม่มีตารางและเมธอดแรกที่รันบนอ็อบเจ็กต์ SQLiteDatabase ที่ฉันมีคือการเรียกไปยังเคียวรี (... ) logcat ของฉันแสดงข้อผิดพลาดของ "I / Database (26434): sqlite return: error code = 1, msg = ไม่มีตารางดังกล่าว: appdata "และแน่นอนว่าตาราง appdata ไม่ได้ถูกสร้างขึ้น

ความคิดเกี่ยวกับสาเหตุใด

ฉันกำลังมองหาวิธีทดสอบว่ามีตารางอยู่หรือไม่ (เพราะถ้าไม่มีข้อมูลก็ไม่อยู่ในนั้นอย่างแน่นอนและฉันไม่จำเป็นต้องอ่านจนกว่าจะเขียนถึงมันซึ่งดูเหมือนจะสร้างตาราง อย่างถูกต้อง) หรือวิธีตรวจสอบให้แน่ใจว่าสร้างขึ้นและว่างเปล่าทันเวลาสำหรับการเรียกครั้งแรกเพื่อสอบถาม (... )

แก้ไข
สิ่งนี้ถูกโพสต์หลังจากสองคำตอบด้านล่าง:
ฉันคิดว่าฉันอาจพบปัญหา ฉันตัดสินใจด้วยเหตุผลบางประการว่าควรสร้าง SQLiteOpenHelper ที่แตกต่างกันสำหรับแต่ละตารางแม้ว่าทั้งสองจะเข้าถึงไฟล์ฐานข้อมูลเดียวกัน ฉันคิดว่าการปรับโครงสร้างโค้ดนั้นใหม่เพื่อใช้ OpenHelper เพียงอันเดียวและการสร้างทั้งสองตารางภายใน onCreate อาจทำงานได้ดีกว่า ...

คำตอบ:


127

ลองอันนี้:

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

ขอบคุณมากสำหรับสิ่งนี้ ใช้งานได้ดี +1
สีเทา

11
อย่าลืมcursor.close();
styler1972

1
ด้วยเหตุผลที่ไม่ทราบชื่อตารางจะคำนึงถึงขนาดตัวพิมพ์ ฉันค่อนข้างใช้select * from sqlite_master where UPPER(name) = 'ROUTES'.
Thupten

4
คำตอบที่ดี แต่ไวยากรณ์ที่เจ็บปวด! ควรเรียกว่า 'isTableExisting ()'
Chris Hatton

1
สิ่งนี้ใช้ได้ผลสำหรับฉัน แต่ฉันต้องตัดคำค้นหาใน try / catch ไม่เช่นนั้นแอปของฉันจะหยุดทำงานเมื่อไม่มีตาราง
Braden Holt

52

ฉันไม่รู้อะไรเกี่ยวกับ Android SQLite API แต่ถ้าคุณสามารถพูดคุยกับมันใน SQL ได้โดยตรงคุณสามารถทำได้:

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

ซึ่งจะช่วยให้มั่นใจได้ว่าตารางจะถูกสร้างขึ้นเสมอและไม่เกิดข้อผิดพลาดใด ๆ หากมีอยู่แล้ว


นั่นคือวิธีที่ฉันสร้างตารางในเมธอด onCreate ภายในคลาส SQLiteOpenHelper ใน Android ขอแนะนำให้ชั้นเรียนนั้นสร้างตารางเนื่องจากอนุญาตให้แอปอัปเดตฐานข้อมูลโดยอัตโนมัติและโดยทั่วไปแล้วจะมีประสิทธิภาพมากกว่า น่าเสียดายที่ codeblock ที่รันโค้ดเหมือนกับที่คุณเขียนไม่ได้ถูกเรียกใช้ในเวลา :(
camperdave

วิธีนี้ใช้งานได้ดีและยังใช้ได้กับดัชนีเช่น "สร้างดัชนีหากไม่มีอยู่ [... ]"
Eric Fortier

5
นี่เป็นคำตอบที่ดีที่สุดสำหรับคำถามที่ถาม
Android ดั้งเดิม

1
แต่คำถามไม่ได้ขอให้สร้าง
10101010

12

แม้ว่าจะมีคำตอบที่ดีมากมายสำหรับคำถามนี้ แต่ฉันก็ได้หาวิธีแก้ปัญหาอื่นที่คิดว่าง่ายกว่า ล้อมรอบข้อความค้นหาของคุณด้วยบล็อกลองและสิ่งต่อไปนี้:

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

มันได้ผลสำหรับฉัน!


1
จะดีกว่าไหมหากใส่คำสั่ง Log ไว้ในบล็อก if () ดูเหมือนว่าหาก SQLiteException ถูกโยนด้วยเหตุผลอื่นที่ไม่ใช่ "ไม่มีตารางดังกล่าว" บันทึกจะระบุว่าคุณกำลังสร้างตารางในขณะที่คุณไม่ได้อยู่จริงๆ

2
การใช้ข้อยกเว้นเพื่อควบคุมกระแสเป็นสิ่งที่น่าละอายไม่มีสอนให้คนอื่นรู้ ตรวจสอบข้อความในลักษณะนั้นให้ทวีคูณ
Nick Cardoso

หากใช้อย่าง จำกัด ฉันไม่คิดว่าจะมีอะไรผิดปกติกับการใช้ข้อยกเว้นในกรณีการใช้งานเช่นที่อธิบายไว้ข้างต้น แน่นอนว่าไม่มีอะไรที่ฉันรู้สึกละอายใจ
robguinness

ฉันคิดว่าe.getMessage().contains("no such table")แย่กว่าการใช้ข้อยกเว้นสำหรับการควบคุมกระแส ทั้งสองแบบเป็นรูปแบบที่ไม่ดี แต่การแยกวิเคราะห์ข้อความแสดงข้อผิดพลาดสำหรับข้อความที่เฉพาะเจาะจงนั้นเป็นรูปแบบที่แย่มาก
jox

11

นี่คือสิ่งที่ฉันทำ:

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

ใช่ปรากฎว่าทฤษฎีในการแก้ไขของฉันถูกต้อง: ปัญหาที่ทำให้เมธอด onCreate ไม่ทำงานคือความจริงที่ว่าSQLiteOpenHelperวัตถุควรอ้างถึงฐานข้อมูลและไม่มีแยกต่างหากสำหรับแต่ละตาราง การบรรจุทั้งสองตารางเป็นหนึ่งเดียวSQLiteOpenHelperช่วยแก้ปัญหาได้


2

คุณบอกว่าคุณได้สร้างคลาสที่ขยายSQLiteOpenHelperและใช้งานonCreateเมธอดนี้ คุณแน่ใจหรือไม่ว่าคุณกำลังดำเนินการฐานข้อมูลทั้งหมดของคุณได้รับการโทรจากชั้นเรียนนั้น คุณควรได้รับSQLiteDatabaseวัตถุผ่านทางSQLiteOpenHelper#getWritableDatabaseและgetReadableDatabaseมิฉะนั้นonCreateเมธอดจะไม่ถูกเรียกเมื่อจำเป็น หากคุณทำเช่นนั้นแล้วให้ตรวจสอบและดูว่าSQLiteOpenHelper#onUpgradeมีการเรียกวิธีการนี้แทนหรือไม่ ถ้าเป็นเช่นนั้นหมายเลขเวอร์ชันของฐานข้อมูลจะเปลี่ยนไปในบางช่วงเวลา แต่ตารางจะไม่ถูกสร้างขึ้นอย่างถูกต้องเมื่อเกิดเหตุการณ์นั้นขึ้น

นอกจากนี้คุณสามารถบังคับให้เกิดการพักผ่อนหย่อนใจของฐานข้อมูลโดยตรวจสอบให้แน่ใจว่าการเชื่อมต่อทั้งหมดถูกปิดและเรียกContext#deleteDatabaseใช้จากนั้นใช้SQLiteOpenHelperเพื่อให้คุณมีวัตถุฐานข้อมูลใหม่


ฉันได้รับวัตถุฐานข้อมูลของฉันผ่านการเรียก getWritableDatabase () ขอโทษที่ฉันลืมระบุ นอกจากนี้ฉันแน่ใจว่า onUpgrade () ไม่ถูกเรียกเนื่องจากเมธอดนั้นมีการเรียก Log.d (... ) เป็นบรรทัดแรกที่ฉันไม่เห็นในฐานข้อมูล ฉันจะลองลบไฟล์ฐานข้อมูลทั้งหมดและเราจะดูว่ามันแก้ไขได้หรือไม่ ...
camperdave

น่าเสียดายที่การลบฐานข้อมูลทั้งหมด (ฉันใช้ root explorer เพื่อล้างไฟล์) ไม่ได้ผล ฉันใช้สองตารางในแอพของฉัน - หนึ่งในนั้นเริ่มต้นอย่างสมบูรณ์แบบ แต่อีกตารางหนึ่งที่ทำให้ฉันมีปัญหามาตลอดไม่ได้
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 เก็บรักษาตาราง sqlite_master ที่มีข้อมูลของตารางและดัชนีทั้งหมดในฐานข้อมูล
  • ดังนั้นที่นี่เราเพียงแค่เรียกใช้คำสั่ง SELECT เราจะได้รับเคอร์เซอร์นับ 1 หากมีตาราง

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 กำลังจะเกิดขึ้นเนื่องจากเมื่อคุณสร้างฐานข้อมูลด้วยตารางเดียวหลังจากนั้นเมื่อใดก็ตามที่คุณสร้างตารางในฐานข้อมูลเดียวกันจะทำให้เกิดข้อผิดพลาดนี้

ในการแก้ไขข้อผิดพลาดนี้คุณต้องสร้างฐานข้อมูลใหม่และภายในเมธอด onCreate () คุณสามารถสร้างหลายตารางในฐานข้อมูลเดียวกัน


0

เงื่อนไขสำคัญคือหากไม่มีอยู่เพื่อตรวจสอบตารางมีอยู่แล้วหรือไม่มีในฐานข้อมูล

ชอบ...

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

0

ฉันเผชิญหน้ากับมันและจัดการกับมันโดยลองจับง่ายๆเหมือนที่ฉันทำในสิ่งที่ฉันต้องการในตารางถ้ามันไม่มีอยู่จะทำให้เกิดข้อผิดพลาดดังนั้นให้จับโดยมีข้อยกเว้นและสร้างขึ้น :)

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 (บริบท "ลอง ... " 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

.....

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.