与文档所说的相比,SQLiteStatement.simpleQueryForLong()的行为有所不同

时间:2014-09-11 04:50:20

标签: android android-sqlite

我正在以下列方式使用simpleQueryForLong()方法:

mResuableStatment = DatabaseHandler.database.compileStatement(
        "SELECT MIN(timestamp) FROM " + TABLE_LOCAITON_LOGGING);

long oldestTimestamp = mResuableStatment.simpleQueryForLong();
  • timestamp是表TABLE_LOCAITON_LOGGING中列的名称。
  • 此时数据库已打开以进行读写。

根据文档 - 如果根本没有行,那么这段代码假设抛出SQLiteDoneException,但真正发生的是当没有行时 - simpleQueryForLong() 返回零(不投掷激励)

更奇怪和意外的是,当我实际将此代码包装在try / catch块中时,每次都会抛出SQLiteDoneException ,即使表中有行:

try {
    long oldestTimestamp = mResuableStatment.simpleQueryForLong();
} catch (SQLiteDoneException e) {
    e.printStackTrace()
}

此行为见于Nexus 5,Galaxy Nexus,LG G2,HTC One X,全部运行Android KitKat。

我有点困惑,因为这迫使我不使用try / catch块,因为如果它被使用 - 无论是否有行,总是抛出异常,反之亦然,文档说的话。 / p>

似乎在我测试的每个设备中 - 如果没有try / catch块,当没有列时 - 它返回零。

请帮助我理解什么是正确的方法,以及我做错了什么,或者只是文档是错误的。

1 个答案:

答案 0 :(得分:2)

实际上,我认为你会发现你的方法错了。

select min(something) ...

永远不会返回零行。如果表没有行,它将返回最小值(如果表有行)或null。如果表格为空时查询只是select something,则可能返回零行,因此可能值得测试。

我已经使用SqlFiddle对此进行了测试,输入命令:

create table xyzzy(a int);
select a from xyzzy;
select min(a) from xyzzy;

第一个select返回零行,第二个返回一行(null)值。

所以我不相信这是引起异常的空表。 可能尝试将(null)转换为long。

你如何修复"这完全取决于您想要使用的数据。依赖于将空行转换为零可能是您想要的也可能不是。例如,如果表中的 为零时间戳,则无法区分该表与空表之间的差异。

这可能是可以接受的,这取决于您的业务要求。

如果你需要区分,我会运行两个查询。第一个将从表中返回count(*)。这保证是包含 numeric 值(无空值)的单行。如果该值为零,则表示该表为空。

如果非零,则然后执行min(column_name),您将获得具有最小时间戳的单行。如果你在那时得到零,你知道它是因为最小时间戳是零。当然除非在那里有一个NULL时间戳,在这种情况下你可能需要做更多的检查。但是,如果您正确构建了架构,我认为这不太可能。

请注意,我不会通常在多用户数据库中提出此建议,因为它可能会导致竞争条件。但我认为它可能还可以,因为应该只有一个用户"这个数据库,你的应用程序。