1

我有不同的查询变体。所有值类型都是字符串!(不要问为什么......)第一个可能看起来像这样:

SELECT * FROM item WHERE arg1=false

arg(s) 的字符串 ("sqlWhere") 如下所示:"arg1=?"

索引 0 处 arg(s)-Array (args) 的字符串如下所示:“false”

这工作正常。我有 715 个结果。

现在,如果我有这样的事情:

SELECT * FROM item WHERE (arg1=40 OR arg2=42) AND arg3=false

我预计会有 110 个结果。但是没有任何结果,没有抛出异常

如果我要在 Firefox SQLite Manager 中生成原始查询:

SELECT COUNT(*) FROM item WHERE (arg1=40 OR arg2=42) AND arg3=false

我会得到错误:“没有这样的列:假”如果我生成这样的查询:

SELECT COUNT(*) FROM item WHERE (arg1=40 OR arg2=42) AND arg3="false"

它不会失败。但。我正在使用选择参数。我读过,他们应该避免这种情况。但他们没有。甚至,如果我为 arg3 = "\"+"false"+"\"" 或 arg3 = "\'+"false"+"\'" 甚至 arg3="'"+"false"+ "'" 不行。也许是android特定的问题?值“false”来自值列表。它用一个空字符串初始化。

查询方法如下所示:

public List<Map<String,String>> getSearchResults(String sqlWhere, String[]args)
    {
        List<Map<String,String>> specs = new ArrayList<Map<String,String>>();
        String[] specnames = this.getSpecNames();

        Cursor cursor = mDb.query(dbSchema.SpecSchema.TABLE_NAME, specnames, sqlWhere, args, null, null, dbSchema.SpecSchema._ID + dbSchema.SORT_ASC);
        cursor.moveToFirst();
        while(!cursor.isAfterLast())
        {
            Map<String, String> temp = new HashMap<String, String>();
            for(int i = 0; i < specnames.length; i++)
                temp.put(specnames[i], cursor.getString(cursor.getColumnIndex(specnames[i])));
            specs.add(temp);

            cursor.moveToNext();
        }

        if(cursor != null)
            cursor.close();

        return specs;
    }
4

3 回答 3

3

使用前面的SQLiteDatabase方法。

SELECT * FROM item WHERE (arg1=40 OR arg2=42) AND arg3=false

应该

SQLiteDatabase db;
String table = "item";
String projection = null;
String selection = "(arg1=? OR arg2=?) AND arg3=?";
String[] selectionArgs = new String[] { "40", "42", "false" };
String sortOrder = null;

db.query(item, projection, selection, selectionArgs, sortOrder);

它没有那么简洁,但更安全,因为它可以防止 SQL 注入并且不太可能导致问题(例如 SQL 语法错误等)。

于 2012-07-27T13:51:58.690 回答
1

的文档SQLiteDatabase.query()说:

selectionArgs - 您可以在选择中包含 ?s,它将被 selectionArgs 中的值替换,以便它们出现在选择中。这些值将绑定为字符串。

当您执行此查询时:

SELECT * FROM item WHERE (arg1=40 OR arg2=42) AND arg3=false

并使用selectionArgs-parameter 绑定参数,整数和布尔值将绑定为字符串。这与您的数据库中的不同。我知道你说你所有的列都是类型的TEXT,但请阅读SQLite 文档

列的类型亲和性是存储在该列中的数据的推荐类型。这里的重要思想是该类型是推荐的,而不是必需的。任何列仍然可以存储任何类型的数据。只是某些列,如果可以选择,会更喜欢使用一个存储类而不是另一个。

这意味着,当您在字符串表中插入整数值时,SQLite 将转换这些值并将它们存储为整数。下一个重点是比较

SQLite 可能会在执行比较之前尝试在存储类 INTEGER、REAL 和/或 TEXT 之间转换值。[...]

  • 作为对列值的简单引用的表达式与列具有相同的亲和性

文档给出了以下示例:

CREATE TABLE t1(
    a TEXT,      -- text affinity
    b NUMERIC,   -- numeric affinity
    c BLOB,      -- no affinity
    d            -- no affinity
);

-- Because column "a" has text affinity, numeric values on the
-- right-hand side of the comparisons are converted to text before
-- the comparison occurs.
SELECT a < 40,   a < 60,   a < 600 FROM t1;
0|1|1

在您的情况下,这意味着以下内容:

  1. 您的TEXT-table 插入整数,然后将其转换(并存储)为INTEGERs。
  2. 进行比较时,您给出TEXT-values (这是您的整数)。这些应该(但不需要)转换为TEXT-values,因为您的表表明它的值是 type TEXT
  3. 你比较INTEGERTEXT这是不相等的,因此不会给你正确的结果。

要将不同的数据类型(除字符串之外)插入 SQLiteDatabase,请使用Prepared Statements

于 2012-07-27T13:38:39.207 回答
0

好的,arg1 是列名,它不是变量名。因此,当您执行第一个查询时,您正在查找列名为 arg1=false 的所有行。在您添加列 arg2 和列 arg3 的所有后续查询中,是否存在列 arg2 和 arg3?您可以发布用于创建表格的代码吗?

于 2012-07-27T13:05:26.540 回答