Strange behaviour of parameterized SQLite query

纵饮孤独 提交于 2019-12-12 11:24:34

问题


(Feel free to improve the question title if you can think of something better.)

Question: Consider the following SQLite query:

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

When I use 1 as the parameter, I expect the query to yield 1, yet it yields 2. Why does this happen?


Additional information:

This is a minimal working example to reproduce the issue (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)));

It might have to do with the fact that the parameter is passed as a string, but, alas, there is no other way to pass parameters to the SQLite API, so I guess I'm not doing anything "wrong" here and it's SQLite's job to convert the value appropriately. I've also observed the following when using a non-parameterized version of the query (this might or might not be relevant for the issue):

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

回答1:


It's said in the rawQuery documentation:

[...] You may include ?s in where clause in the query, which will be replaced by the values from selectionArgs. The values will be bound as Strings.

And, quoting the SQLite doc:

The results of a comparison depend on the storage classes of the operands, according to the following rules [...]

  • An INTEGER or REAL value is less than any TEXT or BLOB value.

As both 1 and 2 are integers, they're both less than '1' (TEXT value). That's why this statement:

SELECT 2 <= '1'

... returns 1 in SQLite.

You should probably use ...

WHERE value <= CAST('1' AS INTEGER)

... instead. Or you can use the fact that all mathematical operators cast both operands to the NUMERIC storage class with WHERE value <= + ?, but this is less clean, imo.

Note that in this query:

SELECT * FROM myTable WHERE _id < ?

... the value of ? will get its affinity adjusted to the affinity of _id column - hence they will be compared as numbers, if _id is NUMERIC.



来源:https://stackoverflow.com/questions/13347531/strange-behaviour-of-parameterized-sqlite-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!