如何检查 Android SQLite 数据库中是不是存在表?

Posted

技术标签:

【中文标题】如何检查 Android SQLite 数据库中是不是存在表?【英文标题】:How does one check if a table exists in an Android SQLite database?如何检查 Android SQLite 数据库中是否存在表? 【发布时间】:2011-03-04 18:54:04 【问题描述】:

我有一个 android 应用程序需要检查数据库中是否已经有记录,如果没有,则处理一些内容并最终插入它,如果数据确实存在,则只需从数据库中读取数据。我正在使用 SQLiteOpenHelper 的子类来创建和获取 SQLiteDatabase 的可重写实例,我认为如果表不存在,它会自动处理创建表(因为执行此操作的代码在 onCreate(... ) 方法)。

但是,当表尚不存在,并且在我拥有的 SQLiteDatabase 对象上运行的第一个方法是调用 query(...) 时,我的 logcat 显示错误“I/Database(26434): sqlite返回:错误代码= 1,msg =没有这样的表:appdata“,并果然,不创建appdata表。

关于为什么的任何想法?

我正在寻找一种方法来测试表是否存在(因为如果不存在,则数据肯定不在其中,并且在写入之前我不需要读取它,这似乎正确创建表格),或者以确保它创建的方式,并且只是空的,并及时呼叫查询(...)

编辑 这是在以下两个答案之后发布的: 我想我可能找到了问题所在。我出于某种原因决定应该为每个表创建一个不同的 SQLiteOpenHelper,即使它们都访问同一个数据库文件。我认为重构该代码只能使用一个OpenHelper,并在它的oncreate内创建两个表可以更好地工作...

【问题讨论】:

【参考方案1】:

试试这个:

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 别忘了cursor.close(); 由于未知原因,表名区分大小写。我宁愿使用select * from sqlite_master where UPPER(name) = 'ROUTES'. 很好的答案,但语法很痛苦!肯定应该被称为“isTableExisting()”。 这对我有用,但我必须将查询包装在 try/catch 中,否则当表不存在时我的应用程序会崩溃。【参考方案2】:

我对 Android SQLite API 一无所知,但如果你能够直接用 SQL 与它对话,你可以这样做:

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

这将确保始终创建表并且不会抛出任何错误(如果它已经存在)。

【讨论】:

这就是我在 SQLiteOpenHelper 类的 onCreate 方法中创建表的方式。在 android 中,建议让该类创建表,因为它允许应用程序自动更新其数据库,并且通常显然更有效。不幸的是,执行代码与您编写的代码非常相似的代码块没有及时运行:( 这很好用,也适用于索引,即:“如果不存在则创建索引 [...]”。 这实际上是所提问题的最佳答案。 但问题并没有要求创建一个【参考方案3】:

虽然这个问题已经有了很多很好的答案,但我想出了另一个我认为更简单的解决方案。用 try 块和以下 catch 包围您的查询:

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.
    

它对我有用!

【讨论】:

将 Log 语句放在 if() 块中不是更好吗?看起来如果 SQLiteException 是由于“没有这样的表”之外的其他原因引发的,日志将表明您正在创建该表,而实际上您并没有。 使用异常来控制流程是一件可耻的事情,而不是教给别人的。以这种方式检查消息,更是如此。 如果谨慎使用,我认为在上述用例中使用异常没有任何问题。当然没有什么让我感到羞耻的。 我认为e.getMessage().contains("no such table") 比使用异常控制流更糟糕。两者都是糟糕的风格,但为特定文本解析错误消息甚至是非常糟糕的风格。【参考方案4】:

这就是我所做的:

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

【讨论】:

【参考方案5】:

是的,事实证明我编辑的理论是正确的:导致 onCreate 方法无法运行的问题是 SQLiteOpenHelper 对象应该引用数据库,而不是每个表都有一个单独的对象。将两张表打包成一张SQLiteOpenHelper 解决了这个问题。

【讨论】:

【参考方案6】:

您提到您创建了一个扩展SQLiteOpenHelper 的类并实现了onCreate 方法。您是否确保使用该类执行所有数据库获取调用?您应该只通过SQLiteOpenHelper#getWritableDatabasegetReadableDatabase 获取SQLiteDatabase 对象,否则在必要时不会调用onCreate 方法。如果您正在这样做,请检查并查看是否正在调用 SQLiteOpenHelper#onUpgrade 方法。如果是这样,那么数据库版本号在某个时间点发生了更改,但发生这种情况时该表从未正确创建。

顺便说一句,您可以通过确保与数据库的所有连接都已关闭并调用Context#deleteDatabase 然后使用SQLiteOpenHelper 为您提供一个新的数据库对象来强制重新创建数据库。

【讨论】:

好吧,我正在通过 getWritableDatabase() 调用获取我的数据库对象,抱歉我忘了指定。另外,我确定没有调用 onUpgrade(),因为该方法有一个 Log.d(...) 调用作为我在数据库中没有看到的第一行。我会尝试删除整个数据库文件,我们会看看是否能以某种方式修复它... 不幸的是,删除整个数据库(我使用根资源管理器清除文件)不起作用。我在我的应用程序中使用了两个表 - 其中一个已完美初始化,但另一个一直给我带来麻烦的却没有。【参考方案7】:
 // @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 的游标。

【讨论】:

【参考方案8】:

Kotlin 解决方案,基于其他人在这里写的:

    fun isTableExists(database: SQLiteDatabase, tableName: String): Boolean 
        database.rawQuery("select DISTINCT tbl_name from sqlite_master where tbl_name = '$tableName'", null)?.use 
            return it.count > 0
         ?: return false
    

【讨论】:

【参考方案9】:
 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;

【讨论】:

【参考方案10】:

no such table exists: error 即将到来,因为一旦您创建了一个包含一个表的数据库,之后每当您在同一个数据库中创建表时都会出现此错误。

要解决此错误,您必须创建新数据库,并且在 onCreate() 方法中,您可以在同一个数据库中创建多个表。

【讨论】:

【参考方案11】:

重要的条件是IF NOT EXISTS检查表是否已经存在或不在数据库中

喜欢...

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

【讨论】:

【参考方案12】:

我遇到了这个问题并通过尝试捕获来处理它,就像我在表中做我想要的那样,如果它不存在会导致错误,所以通过异常捕获它并创建它:)

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

【讨论】:

【参考方案13】:

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

.....

【讨论】:

以上是关于如何检查 Android SQLite 数据库中是不是存在表?的主要内容,如果未能解决你的问题,请参考以下文章

带有 Sqlite 的 Android - 如何检查表是不是存在以及是不是为空

Android中是怎样防止SQL注入的?

检查查询是不是在 Android 的 sqlite 中成功

sqlite3:创建没有列的表

如何在 Android Studio 上获取 Sqlite 数据库中插入数据的实时视图

android sqlite3命令行检查自己的代码操作数据库是否正确