参数化SQLite查询的奇怪行为

Hei*_*nzi 4 sql sqlite android parameterized-query

(如果你能想到更好的东西,请随意改进问题标题.)

问题:考虑以下SQLite查询:

SELECT COUNT(*)
  FROM (SELECT 1 AS value UNION SELECT 2 AS value)
 WHERE value <= ?
Run Code Online (Sandbox Code Playgroud)

当我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)));
Run Code Online (Sandbox Code Playgroud)

可能与参数作为字符串传递这一事实有关,但是,唉,没有其他方法可以将参数传递给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
Run Code Online (Sandbox Code Playgroud)

rai*_*7ow 5

它在rawQuery文档中说:

[...]您可以在查询中的where子句中包含?s,它将被selectionArgs中的值替换.这些值将绑定为字符串.

并且,引用SQLite文档:

根据以下规则,比较结果取决于操作数的存储类[...]

  • INTEGER或REAL值小于任何TEXT或BLOB值.

由于1和2 都是整数,因此它们都小于'1'(TEXT值).这就是为什么这句话:

SELECT 2 <= '1'
Run Code Online (Sandbox Code Playgroud)

...在SQLite中返回1.

你可能应该使用......

WHERE value <= CAST('1' AS INTEGER)
Run Code Online (Sandbox Code Playgroud)

......而是.或者您可以使用这样的事实:所有数学运算符都将操作数转换为NUMERIC存储类WHERE value <= + ?,但这不太干净,imo.

请注意,在此查询中:

SELECT * FROM myTable WHERE _id < ?
Run Code Online (Sandbox Code Playgroud)

... ... 的值?会将其亲和力调整为_id 的亲和力 - 因此它们将作为数字进行比较,如果_id是NUMERIC.