Question

(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
Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top