4

(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
4

1 に答える 1

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)

... 代わりは。または、すべての数学演算子が両方のオペランドを で NUMERIC ストレージ クラスにキャストするという事実を使用できますがWHERE value <= + ?、これはきれいではありません。

このクエリでは、次の点に注意してください。

SELECT * FROM myTable WHERE _id < ?

...の値は、カラム?のアフィニティに調整されたアフィニティを取得し_id _idます。したがって、 NUMERICの場合は数値として比較されます。

于 2012-11-12T16:40:24.180 に答える