如何将 INTEGER/NULL 绑定到 a ? Android 中带有 rawQuery selectionArgs 的占位符?
How to bind INTEGER/NULL to a ? placeholder with rawQuery selectionArgs in Android?
下面的任何内容都可以更改以达到有效的解决方案!我可以完全控制下面的所有内容schema/data/query/code,所以任何合理的改进都是欢迎:我正在寻找 simple/clean/to-the-point 解决方案。例如,进行两个不同的查询(= ?
和 is null
)是 最后的手段。
问题
我想更改下面的代码,这样我就可以调用 listCategoriesIn(1)
和 listCategoriesIn(null)
,它们都给出了正确的预期结果。
我无法让 listCategoriesIn(null)
使用 WHERE
子句,例如 c.parent = ?
.
- 是否可以将
INTEGER
或 NULL
绑定到 = ?
?
- 我应该如何修改
WHERE
子句以使其适用于这两种情况?
- 我还可以更改什么以使其正常工作?
Table
CREATE TABLE Category (
_id INTEGER NOT NULL,
name VARCHAR NOT NULL,
parent INTEGER NULL --< important bit
CONSTRAINT fk_Category_parent
REFERENCES Category(_id)
ON UPDATE CASCADE
ON DELETE CASCADE,
PRIMARY KEY(_id AUTOINCREMENT),
UNIQUE(name)
);
示例数据
INSERT INTO Category
(_id, parent, name)
SELECT 0, NULL, 'cat0' --< expected for listCategoriesIn(null)
UNION SELECT 1, NULL, 'cat1' --< expected for listCategoriesIn(null)
UNION SELECT 11, 1, 'cat1-1' --< expected for listCategoriesIn(1)
UNION SELECT 12, 1, 'cat1-2' --< expected for listCategoriesIn(1)
UNION SELECT 121, 12, 'cat1-2-1'
UNION SELECT 122, 12, 'cat1-2-2'
UNION SELECT 13, 1, 'cat1-3' --< expected for listCategoriesIn(1)
UNION SELECT 131, 13, 'cat1-3-1'
UNION SELECT 2, NULL, 'cat2' --< expected for listCategoriesIn(null)
UNION SELECT 21, 2, 'cat2-1'
UNION SELECT 3, NULL, 'cat3' --< expected for listCategoriesIn(null)
;
查询
IRL 我正在使用涉及视图、子查询、多个 JOIN 的更复杂的。
select
c.*,
(select count() from Category where parent = c._id) as count
from Category c
where c.parent = ? --< important bit
;
错误代码 #1
public Cursor listCategoriesIn(SQLiteDatabase db, Long categoryID) {
// public Cursor SQLiteDatabse.rawQuery(String sql, String[] selectionArgs);
return db.rawQuery(CATEGORY_QUERY, new String[] {
String.valueOf(categoryID)
});
}
listCategoriesIn(1)
: works OK
listCategoriesIn(null)
: the resulting Cursor is empty, possibly = 'null'
or = NULL
is bound.
错误代码 #2
public Cursor listCategoriesIn(SQLiteDatabase db, Long categoryID) {
// public Cursor SQLiteDatabse.rawQuery(String sql, String[] selectionArgs);
return db.rawQuery(CATEGORY_QUERY, new String[] {
categoryID == null? null : categoryID.toString()
});
}
listCategoriesIn(1)
: works OK
listCategoriesIn(null)
:
java.lang.IllegalArgumentException: the bind value at index 1 is null
我认为您需要在字段为 NULL 时发送不同的 SQL 语句。
public Cursor listCategoriesIn(SQLiteDatabase db, Long categoryID) {
if(categoryID == null)
return db.rawQuery(CATEGORY_QUERY_NULL, null);
else
return db.rawQuery(CATEGORY_QUERY, new String[] { categoryID.toString() });
}
其中 CATEGORY_QUERY_NULL 是与 CATEGORY_QUERY 相同的查询,但使用 c.parent IS NULL
而不是 c.parent = ?
。有关详细信息,请参阅此 answer。
在它上睡觉并开始新的一天后,我顿悟了,没有重复查询是可能的:
where c.parent = ? or (? = 'null' and c.parent is null)
但是我们需要复制参数,这里是相应的 Java 调用:
public Cursor listCategoriesIn(SQLiteDatabase db, Long categoryID) {
return db.rawQuery(CATEGORY_QUERY, new String[] {
String.valueOf(categoryID), String.valueOf(categoryID)
});
}
当 categoryID
为 null
时没有 NPE,因为它绑定为 "null"
(请参阅 valueOf
)。将 null->'null'
传递给驱动程序会激活 WHERE
子句的第二部分,当然 INTEGER
值中的 none 将是 = 'null'
,因此第一部分不会玩吧。
这个技巧之所以有效,是因为 rawQuery
binds everything as String
s and the SQLite engine can handle comparing INTEGER
s with numbers in a TEXT
. I'm sure the details can be found in the SQLite Datatypes documentation.
下面的任何内容都可以更改以达到有效的解决方案!我可以完全控制下面的所有内容schema/data/query/code,所以任何合理的改进都是欢迎:我正在寻找 simple/clean/to-the-point 解决方案。例如,进行两个不同的查询(= ?
和 is null
)是 最后的手段。
问题
我想更改下面的代码,这样我就可以调用 listCategoriesIn(1)
和 listCategoriesIn(null)
,它们都给出了正确的预期结果。
我无法让 listCategoriesIn(null)
使用 WHERE
子句,例如 c.parent = ?
.
- 是否可以将
INTEGER
或NULL
绑定到= ?
? - 我应该如何修改
WHERE
子句以使其适用于这两种情况? - 我还可以更改什么以使其正常工作?
Table
CREATE TABLE Category (
_id INTEGER NOT NULL,
name VARCHAR NOT NULL,
parent INTEGER NULL --< important bit
CONSTRAINT fk_Category_parent
REFERENCES Category(_id)
ON UPDATE CASCADE
ON DELETE CASCADE,
PRIMARY KEY(_id AUTOINCREMENT),
UNIQUE(name)
);
示例数据
INSERT INTO Category
(_id, parent, name)
SELECT 0, NULL, 'cat0' --< expected for listCategoriesIn(null)
UNION SELECT 1, NULL, 'cat1' --< expected for listCategoriesIn(null)
UNION SELECT 11, 1, 'cat1-1' --< expected for listCategoriesIn(1)
UNION SELECT 12, 1, 'cat1-2' --< expected for listCategoriesIn(1)
UNION SELECT 121, 12, 'cat1-2-1'
UNION SELECT 122, 12, 'cat1-2-2'
UNION SELECT 13, 1, 'cat1-3' --< expected for listCategoriesIn(1)
UNION SELECT 131, 13, 'cat1-3-1'
UNION SELECT 2, NULL, 'cat2' --< expected for listCategoriesIn(null)
UNION SELECT 21, 2, 'cat2-1'
UNION SELECT 3, NULL, 'cat3' --< expected for listCategoriesIn(null)
;
查询
IRL 我正在使用涉及视图、子查询、多个 JOIN 的更复杂的。
select
c.*,
(select count() from Category where parent = c._id) as count
from Category c
where c.parent = ? --< important bit
;
错误代码 #1
public Cursor listCategoriesIn(SQLiteDatabase db, Long categoryID) {
// public Cursor SQLiteDatabse.rawQuery(String sql, String[] selectionArgs);
return db.rawQuery(CATEGORY_QUERY, new String[] {
String.valueOf(categoryID)
});
}
listCategoriesIn(1)
: works OK
listCategoriesIn(null)
: the resulting Cursor is empty, possibly= 'null'
or= NULL
is bound.
错误代码 #2
public Cursor listCategoriesIn(SQLiteDatabase db, Long categoryID) {
// public Cursor SQLiteDatabse.rawQuery(String sql, String[] selectionArgs);
return db.rawQuery(CATEGORY_QUERY, new String[] {
categoryID == null? null : categoryID.toString()
});
}
listCategoriesIn(1)
: works OK
listCategoriesIn(null)
: java.lang.IllegalArgumentException: the bind value at index 1 is null
我认为您需要在字段为 NULL 时发送不同的 SQL 语句。
public Cursor listCategoriesIn(SQLiteDatabase db, Long categoryID) {
if(categoryID == null)
return db.rawQuery(CATEGORY_QUERY_NULL, null);
else
return db.rawQuery(CATEGORY_QUERY, new String[] { categoryID.toString() });
}
其中 CATEGORY_QUERY_NULL 是与 CATEGORY_QUERY 相同的查询,但使用 c.parent IS NULL
而不是 c.parent = ?
。有关详细信息,请参阅此 answer。
在它上睡觉并开始新的一天后,我顿悟了,没有重复查询是可能的:
where c.parent = ? or (? = 'null' and c.parent is null)
但是我们需要复制参数,这里是相应的 Java 调用:
public Cursor listCategoriesIn(SQLiteDatabase db, Long categoryID) {
return db.rawQuery(CATEGORY_QUERY, new String[] {
String.valueOf(categoryID), String.valueOf(categoryID)
});
}
当 categoryID
为 null
时没有 NPE,因为它绑定为 "null"
(请参阅 valueOf
)。将 null->'null'
传递给驱动程序会激活 WHERE
子句的第二部分,当然 INTEGER
值中的 none 将是 = 'null'
,因此第一部分不会玩吧。
这个技巧之所以有效,是因为 rawQuery
binds everything as String
s and the SQLite engine can handle comparing INTEGER
s with numbers in a TEXT
. I'm sure the details can be found in the SQLite Datatypes documentation.