SQLite的rawQuery selectionArgs两个和整数字段整数、字段、两个、SQLite

2023-09-05 02:03:17 作者:想吃炸鸡,想着想

由于Android的文件称,rawQuery方法的selectionArgs两个参数解析为字符串。

As the Android documents says, the selectionArgs parameters of the rawQuery method is parsed as strings.

SQLiteDatabase.rawQuery(SQL字符串,字符串[] selectionArgs两个)

SQLiteDatabase.rawQuery(String sql, String[] selectionArgs)

selectionArgs两个:你可能包括S在哪里查询条款,   这将通过从selectionArgs两个的值来替换。   该值将被绑定为字符串。

selectionArgs: 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.

但今天,我面临着使我的一天中的很大一部分的问题。想象一下下面的查询:

But today, I was faced with a problem that took a great part of my day. Imagine the following query:

SELECT * FROM TABLE_A WHERE IFNULL(COLUMN_A, 0) >= 15

COLUMN_A是INTEGER。该表有参加该标准约10行。运行在数据库编辑器的查询时,结果总是正确的,但是,在智能手机上,该语句总是返回任何行。

COLUMN_A is INTEGER. The table has about 10 rows that attends to that criteria. Running the query on a database editor, the result was always correct, but, on the smartphone, the statement always returned no rows.

一段时间后,一个改变了查询:

After some time, a changed the query to:

SELECT * FROM TABLE_A WHERE IFNULL(COLUMN_A, 0) >= '15'

和编辑器返回任何行,就像机器人。因此,改变了查询:

and the editor returned no rows, just like Android. So, changing the query to:

SELECT * FROM TABLE_A WHERE CAST(IFNULL(COLUMN_A, 0) as INTEGER) >= '15'

解决了这个问题。另一项测试,这是做的是:

solved the problem. Another test that was done was:

SELECT * FROM TABLE_A WHERE COLUMN_A >= '15'

另外,返回正确的结果。

also, returned the correct result.

这似乎是,涉及的方式,机器人界定的参数到查询(字符串)与IFNULL子句中的问题。

This appears to be a problem that involves the way that Android bounds the parameters to the query (as strings) with the IFNULL clause.

因此​​,没有任何人知道为什么会这样?是否有任何建议,以解决这一不使用CAST上查询?

So, does anybody knows why this happened? Are there any suggestions to solve this without using CAST on the query?

推荐答案

为什么你的的原因绑定的你的价值观,以在第一时间查询是,你想从prevent自己的SQL注入的。

The reason why you bind your values to the query in the first place is, that you want to prevent yourself from SQL-injections.

由于命令(可注入到你的实际的查询,显示在链接的文章)都是字符串,字符串,数据类型是比较危险的。

Since commands (which can be injected into your actual query as show in the linked article) are strings, the string-datatype is the more "dangerous" one.

如果用户试图注入一些code到字段,它应该只需要数字,你尝试转换/解析输入到一个整数(把值到您的查询之前),你会得到一个异常立刻。用字符串,不存在这样的一种安全性。为此,他们必须很可能逃过一劫。

If a user tries to inject some code into your field which should only take numbers and you try to cast/parse the input to an integer (before putting the value into your query), you'll get an exception right away. With a string, there is no such kind security. Therefor, they have to be escaped probably.

这的也许的是,绑定值PTED为字符串的所有跨$ P $的原因。

That might be the reason that the bind values are all interpreted as strings.

要prevent从SQL-注射您的应用程序,也加快了多个数据库操作(使用相同的命令,但不同的值),你应该用prepared声明。正确的类在Android SDK是SQLiteStatement.

To prevent your application from SQL-Injections and also speed up multiple database-operations (with the same command but different values), you should use "prepared statements". The correct class in the android SDK is SQLiteStatement.

要创建一个prepared语句,使用compileStatement()-method你的 SQLiteDatabase -object并绑定相应的值(应替换为 -marks在您的查询)使用正确的 bindXX() - 方法(这是从SQLiteProgram):

To create a prepared statement, you use the compileStatement()-method of your SQLiteDatabase-object and bind the corresponding values (which should be replaced with the ?-marks in your query) using the correct bindXX()-method (which are inherited from SQLiteProgram):

SQLiteDatabase db = dbHelper.getWritableDatabase();
SQLiteStatement stmt = db.compileStatement("INSERT INTO SomeTable (name, age) values (?,?)");
stmt.bindString(1, "Jon");
stmt.bindLong(2, 48L);
stmt.execute();

从这个旧的问题所采取的示例:如何使用$ P $ SQLite中的机器人ppared声明

当查询的东西,你需要的数据类型为整数的,你可以直接将其插入查询字符串。 但是:

When querying for something and you need the data-type to be integer, you can directly insert it into the query-string. BUT:

请务必确认在code的投入,其实之前做任何与它的工作,因为你永远不知道什么人可以给你作为他们的意见。所以,做这样的事情应该是可以接受的:

Be sure to validate the input "in code", before actually doing any work with it, because you never know what people might give you as their input. So, doing something like this should be acceptable:

int number;
try{
  number = Integer.parseInt(numerical_input.getText());
} catch (NumberFormatException e){
  // Input wasn't a number, prompt user to input something accurate
}
// Input was a number, we should be fine:
db.rawQuery("SELECT * FROM TABLE_A WHERE IFNULL(COLUMN_A, 0) >= "+number, null);

在安卓(及任何新时代的UI组件框架),你有更多的选择,它可以帮助你执行仅包含数字的的政策,例如输入类型。

In Android (and any new-age UI component framework), you have some more options which can help you enforce the "numbers-only" policy, for example the "input types".