Làm cách nào để kiểm tra xem một bảng có tồn tại trong cơ sở dữ liệu Android SQLite hay không?


87

Tôi có một ứng dụng android cần kiểm tra xem đã có bản ghi trong cơ sở dữ liệu chưa và nếu chưa, hãy xử lý một số thứ và cuối cùng chèn nó và chỉ cần đọc dữ liệu từ cơ sở dữ liệu nếu dữ liệu tồn tại. Tôi đang sử dụng một lớp con của SQLiteOpenHelper để tạo và nhận một phiên bản SQLiteDatabase có thể ghi lại được, mà tôi nghĩ rằng nó sẽ tự động xử lý việc tạo bảng nếu nó chưa tồn tại (vì mã để làm điều đó nằm trong onCreate (... ) phương pháp).

Tuy nhiên, khi bảng KHÔNG tồn tại và phương pháp đầu tiên chạy trên đối tượng SQLiteDatabase mà tôi có là lệnh gọi truy vấn (...), logcat của tôi hiển thị lỗi "I / Database (26434): sqlite return: error code = 1, msg = no such table: appdata ", và chắc chắn, bảng appdata không được tạo.

Bất kỳ ý tưởng về lý do tại sao?

Tôi đang tìm một phương pháp để kiểm tra xem bảng có tồn tại hay không (bởi vì nếu không, dữ liệu chắc chắn không có trong đó và tôi không cần đọc nó cho đến khi tôi ghi vào nó, điều này dường như tạo ra bảng đúng cách), hoặc một cách để đảm bảo rằng nó được tạo và chỉ trống, trong thời gian cho lệnh gọi truy vấn đầu tiên (...)

CHỈNH SỬA
Điều này được đăng sau hai câu trả lời bên dưới:
Tôi nghĩ rằng tôi có thể đã tìm ra vấn đề. Vì một số lý do, tôi đã quyết định rằng một SQLiteOpenHelper khác được cho là phải được tạo cho mỗi bảng, mặc dù cả hai đều truy cập vào cùng một tệp cơ sở dữ liệu. Tôi nghĩ rằng cấu trúc lại mã đó để chỉ sử dụng một OpenHelper và tạo cả hai bảng bên trong nó onCreate có thể hoạt động tốt hơn ...

Câu trả lời:


127

Hãy thử cái này:

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

Cảm ơn rất nhiều vì điều này. Hoạt động tuyệt vời. +1
Màu xám,

11
Đừng quêncursor.close();
stylist1972

1
Vì lý do không xác định, tên bảng phân biệt chữ hoa chữ thường. Tôi thà sử dụngselect * from sqlite_master where UPPER(name) = 'ROUTES'.
Thupten

4
Câu trả lời hay nhưng ngữ pháp đau đớn! Chắc chắn sẽ được gọi là 'isTableExisting ()'.
Chris Hatton

1
Điều này hiệu quả với tôi nhưng tôi phải kết thúc truy vấn trong một lần thử / bắt nếu không ứng dụng của tôi sẽ bị lỗi khi bảng không tồn tại.
Braden Holt

52

Tôi không biết gì về API SQLite của Android, nhưng nếu bạn có thể nói chuyện trực tiếp với nó trong SQL, bạn có thể làm điều này:

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

Điều này sẽ đảm bảo rằng bảng luôn được tạo và không có bất kỳ lỗi nào nếu nó đã tồn tại.


Đó là cách tôi tạo bảng trong phương thức onCreate bên trong lớp SQLiteOpenHelper. Trong android, bạn nên để lớp đó tạo bảng, vì nó cho phép ứng dụng tự động cập nhật cơ sở dữ liệu của nó và nói chung là hiệu quả hơn. Thật không may, đó codeblock đó thực thi mã giống như một bạn đã viết là không nhận được ran trong thời gian :(
camperdave

Điều này hoạt động tuyệt vời và cũng hoạt động với các chỉ mục, tức là: "tạo chỉ mục nếu không tồn tại [...]".
Eric Fortier

5
Đây thực sự là câu trả lời tốt nhất cho câu hỏi được hỏi.
Android gốc

1
nhưng câu hỏi không yêu cầu để tạo ra một
10101010

12

Mặc dù đã có rất nhiều câu trả lời hay cho câu hỏi này, nhưng tôi đã nghĩ ra một giải pháp khác mà tôi nghĩ là đơn giản hơn. Bao quanh truy vấn của bạn bằng một khối thử và bắt sau:

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

Nó đã làm việc cho tôi!


1
Sẽ tốt hơn nếu đặt câu lệnh Log bên trong khối if ()? Có vẻ như nếu SQLiteException được ném vì một lý do khác ngoài "không có bảng như vậy", nhật ký sẽ cho biết rằng bạn đang tạo bảng, trong khi thực tế thì không.

2
Sử dụng ngoại lệ để kiểm soát dòng chảy là điều đáng xấu hổ, không được dạy cho người khác. Kiểm tra tin nhắn theo cách đó, gấp đôi như vậy.
Nick Cardoso

Nếu được sử dụng ít, tôi không nghĩ có gì sai khi sử dụng các ngoại lệ trong các trường hợp sử dụng như mô tả ở trên. Chắc chắn không có gì tôi xấu hổ.
robguinness

Tôi nghĩ e.getMessage().contains("no such table")là tệ hơn việc sử dụng ngoại lệ cho luồng điều khiển. Cả hai đều là phong cách tồi, nhưng phân tích cú pháp thông báo lỗi cho văn bản cụ thể thậm chí còn rất tệ.
jox

11

Đây là những gì tôi đã làm:

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

Đúng vậy, hóa ra lý thuyết trong bản chỉnh sửa của tôi đã đúng: vấn đề khiến phương thức onCreate không chạy, thực tế là SQLiteOpenHelpercác đối tượng nên tham chiếu đến cơ sở dữ liệu chứ không phải có một cái riêng cho mỗi bảng. Đóng gói cả hai bảng thành một đã SQLiteOpenHelpergiải quyết được vấn đề.


2

Bạn đã đề cập rằng bạn đã tạo một lớp mở rộng SQLiteOpenHelpervà triển khai onCreatephương thức. Bạn có đảm bảo rằng bạn đang thực hiện tất cả các lệnh gọi thu được cơ sở dữ liệu của mình với lớp đó không? Bạn chỉ nên lấy SQLiteDatabasecác đối tượng thông qua SQLiteOpenHelper#getWritableDatabasegetReadableDatabasenếu không thì onCreatephương thức sẽ không được gọi khi cần thiết. Nếu bạn đang làm điều đó, hãy kiểm tra và xem SQLiteOpenHelper#onUpgradephương thức thứ có được gọi thay thế hay không. Nếu vậy, thì số phiên bản cơ sở dữ liệu đã được thay đổi tại một số thời điểm nhưng bảng không bao giờ được tạo đúng cách khi điều đó xảy ra.

Ngoài ra, bạn có thể buộc tạo lại cơ sở dữ liệu bằng cách đảm bảo rằng tất cả các kết nối với nó đã được đóng và gọi Context#deleteDatabase, sau đó sử dụng SQLiteOpenHelperđể cung cấp cho bạn một đối tượng db mới.


Chà, tôi đang nhận đối tượng cơ sở dữ liệu của mình thông qua lệnh gọi getWlikeDatabase (), xin lỗi, tôi đã quên chỉ định điều đó. Ngoài ra, tôi chắc chắn rằng onUpgrade () không được gọi, vì phương thức đó có lệnh gọi Log.d (...) là dòng đầu tiên mà tôi không thấy trong cơ sở dữ liệu. Tôi sẽ cố gắng xóa toàn bộ tập tin cơ sở dữ liệu, và chúng ta sẽ thấy nếu điều đó bằng cách nào đó sửa chữa nó ...
camperdave

Thật không may, việc xóa toàn bộ cơ sở dữ liệu (tôi đã sử dụng root explorer để xóa tệp) đã không hoạt động. Tôi sử dụng hai bảng trong ứng dụng của mình - một trong số chúng được khởi tạo hoàn hảo, tuy nhiên bảng còn lại khiến tôi gặp rắc rối thì không.
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 duy trì bảng sqlite_master chứa thông tin của tất cả các bảng và chỉ mục trong cơ sở dữ liệu.
  • Vì vậy, ở đây chúng tôi chỉ đơn giản là chạy lệnh SELECT trên nó, chúng tôi sẽ nhận được con trỏ có đếm 1 nếu bảng tồn tại.

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 sắp xảy ra bởi vì khi bạn tạo cơ sở dữ liệu với một bảng sau đó bất cứ khi nào bạn tạo bảng trong cùng cơ sở dữ liệu, nó sẽ xuất hiện lỗi này.

Để giải quyết lỗi này, bạn phải tạo cơ sở dữ liệu mới và bên trong phương thức onCreate (), bạn có thể tạo nhiều bảng trong cùng một cơ sở dữ liệu.


0

Điều kiện quan trọng NẾU KHÔNG TỒN TẠI để kiểm tra bảng đã tồn tại hay chưa trong cơ sở dữ liệu

giống...

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

0

tôi đã đối mặt với điều đó và đối phó với nó bằng cách thử bắt nó đơn giản như tôi làm những gì tôi muốn trong bảng nếu nó không tồn tại sẽ gây ra lỗi vì vậy hãy bắt nó bằng các ngoại lệ và tạo nó :)

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

.....

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.