(如果你能想到更好的东西,请随意改进问题标题。)
问题:请考虑以下SQLite查询:
SELECT COUNT(*)
FROM (SELECT 1 AS value UNION SELECT 2 AS value)
WHERE value <= ?
当我使用1
作为参数时,我期望该查询产生1
,但它会产生2
。为什么会这样?
其他信息:
这是重现问题的最小工作示例(Android):
Cursor c = db.rawQuery(
"SELECT COUNT(*) " +
" FROM (SELECT 1 AS value UNION SELECT 2 AS value) " +
" WHERE value <= ? ",
new String[] {String.valueOf(1)});
c.moveToFirst();
Log.i("", "Result: " + String.valueOf(c.getInt(0)));
可能与参数作为字符串传递这一事实有关,但是,唉,没有其他方法可以将参数传递给SQLite API,所以我想我是这里没有做任何“错误”的事情,SQLite的工作是适当地转换价值。在使用查询的非参数化版本时,我也观察到以下情况(这可能与问题有关,也可能不相关):
SELECT COUNT(*)
FROM (SELECT 1 AS value UNION SELECT 2 AS value)
WHERE value <= 1 -- yields 1
SELECT COUNT(*)
FROM (SELECT 1 AS value UNION SELECT 2 AS value)
WHERE value <= '1' -- yields 2
答案 0 :(得分:5)
在rawQuery
文档中说:
[...]您可以在查询中的where子句中包含?s,它将被selectionArgs中的值替换。 这些值将绑定为字符串。
并引用SQLite doc:
比较的结果取决于的存储类别 操作数,根据以下规则[...]
- INTEGER或REAL值小于任何TEXT或BLOB值。
由于1和2 都是整数,它们都小于'1'(TEXT值)。这就是为什么这句话:
SELECT 2 <= '1'
...在SQLite中返回1.
您应该使用......
WHERE value <= CAST('1' AS INTEGER)
......相反。或者你可以使用这样的事实,即所有数学运算符都将操作数转换为带有WHERE value <= + ?
的NUMERIC存储类,但这不太干净,imo。
请注意,在此查询中:
SELECT * FROM myTable WHERE _id < ?
... the value of ?
will get its affinity adjusted to the affinity of _id
column - 因此如果_id
为NUMERIC,则会将它们作为数字进行比较。