我正在以下列方式使用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块,当没有列时 - 它返回零。
请帮助我理解什么是正确的方法,以及我做错了什么,或者只是文档是错误的。
答案 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时间戳,在这种情况下你可能需要做更多的检查。但是,如果您正确构建了架构,我认为这不太可能。
请注意,我不会通常在多用户数据库中提出此建议,因为它可能会导致竞争条件。但我认为它可能还可以,因为应该只有一个用户"这个数据库,你的应用程序。