我正在尝试从数据库中选择一些数据,我有两片代码来执行此操作:
cursor = builder.query(db,
new String[]{"col1", "col2", "col3"},
"id = ?", new String[]{getSID(db)}, null, null, null);
和
cursor = builder.query(db,
new String[]{"col1", "col2", "col3"},
"id = " + getSID(db), null, null, null, null);
它们之间的区别在于,根据文档,第一个似乎更正确,但它也不起作用 - 光标是空的。而不是第二个 - 我得到了我需要的所有数据。
所以我尝试在我的电脑上使用数据库副本执行不同的SQL查询,这就是我所拥有的:
SELECT col1, col2, col3 FROM SomeTables WHERE (id = '42')
这个不起作用(这个查询显然等于查询,由第一个代码示例生成)
SELECT col1, col2, col3 FROM SomeTables WHERE (id = 42)
这个工作正常(等于从第二个代码示例查询)。
据我所知,SQLite应该自动执行类型转换,但出了点问题,我不知道为什么。您对如何修复第一个代码示例有什么想法吗? (或者,也许,数据库?)
如果重要,请使用CREATE
字段的表格的简化id
脚本:
CREATE TABLE SomeTable ( ID PRIMARY KEY, col1, col2, [...] )
UPD:顺便说一句,getSID(db)返回String Object。
答案 0 :(得分:8)
那个查询参数只能是字符串,这是Android数据库API中一个可怕的设计错误。
尽管文档说的是,但您应该仅将参数用于实际的字符串值;整数值可以安全地直接嵌入到SQL字符串中。 (对于blob,您必须使用接受ContentValues
的函数。)
请注意,虽然SQLite使用dynamic typing,但在大多数情况下,不同类型的值不比较相等(SELECT 42='42';
返回0
)。
在某些情况下,SQLite 会自动转换由type affinity引起的值(在您的情况下,如果您将id
列声明为INTEGER
,则会发生这种情况),但这是违反直觉的,所以不应该依赖它。
答案 1 :(得分:2)
根据SQLite documentation,
SQLite版本3数据库中的任何列(INTEGER PRIMARY KEY列除外)都可用于存储任何存储类的值。
在我的情况下,这意味着我们无法确定哪些数据类型将存储在列中。如果您可以在数据类型放入数据库时控制和转换数据类型 - 在向数据库添加数据时可以将id
值转换为TEXT
并轻松使用selectionArgs
。但这不是我的问题的答案,因为我必须按原样处理数据库内容。
所以,可能的解决方案:
a)在selection
字符串中嵌入整数值,而不将它们包装到'
中:
cursor = builder.query(db,
new String[]{"col1", "col2", "col3"},
"id = " + getSID(db), null, null, null, null);
b)来自selectionArgs的投射值:CAST(? as INTEGER)
或CAST(id AS TEXT)
。我认为,将列转换为TEXT
是更好的解决方案,因为右操作数总是TEXT
,但左边的操作数可以是任何内容。所以:
cursor = builder.query(db,
new String[]{"col1", "col2", "col3"},
"CAST(id AS TEXT) = ?",
new String[]{getSID(db)}, null, null, null);
答案 2 :(得分:1)
在传递给查询之前,您需要将 int id
转换为string
,因为参数数组的类型为字符串。例如:
cursor = builder.query(db, new String[]{"col1", "col2", "col3"},
"id = ?", new String[]{String.valueOf(getSID(db))}, null, null, null);
它在第二类查询中工作的原因是因为您使用字符串附加整数值,该字符串会自动将int转换为String。例如:
int i = 10;
String s = i + ""; //now 10 is in string