2012-11-12 222 views
4

(随意提高问题的标题,如果你能想到的更好的东西。)奇怪的行为

问题:考虑以下SQLite的查询:

SELECT COUNT(*) 
    FROM (SELECT 1 AS value UNION SELECT 2 AS value) 
WHERE value <= ? 

当我使用1作为参数,I 预计查询产生1,但它产生2。为什么会发生?


信息

这是一个最小的工作示例重现该问题(安卓):

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的工作,转换值a​​p propriately。我还观察到使用查询的非参数化的版本(这可能是也可能不是相关的问题)时,以下几点:

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

是有意义的。 char'1'= 49 – njzk2

+0

也许你可以使用SELECT'1'和SELECT'2' – njzk2

回答

5

这是rawQuery文档中说:

[...]你可以在查询中的where子句中包含?,它将被来自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存储类,但这不太干净。

注意,在此查询:

SELECT * FROM myTable WHERE _id < ? 

... the value of ? will get its affinity adjusted to the affinity of _idcolumn - 因此,他们将作为数字相比,如果_id是数字。

+1

就是这样,谢谢!因此,只有在将它们直接与数据库列进行比较时,才能对参数进行自动类型调整......这很好理解。 – Heinzi