SQLite rawQuery + String.format = "The statement has 0 parameters."?

SQLite rawQuery + String.format = "The statement has 0 parameters."?

我正在尝试在 android 中执行 sqlite rawquery。我从我的设备上下载了数据库,并使用 "sqlite query browser" windows 程序试错,直到我得到我想要的。现在的问题是我有我需要的字符串,我似乎无法将参数输入其中,我怀疑它只是某种字符串转义缺陷。

我要执行的查询是

SELECT lis.name from listItemSuggestion lis LEFT JOIN listItem li ON lis.name = li.name WHERE li.name is NULL AND lis.name LIKE '%a%'

其中“%a%”中的 a 需要是可变参数。我在代码中所做的是这样的:

getReadableDatabase().rawQuery(
        String.format("SELECT lis.%s from %s lis LEFT JOIN %s li ON lis.%s = li.%s WHERE li.%s is NULL AND lis.%s LIKE '%%?%%';",
            ListItemSuggestion.COLUMN_NAME,
            ListItemSuggestion.TABLE_NAME,
            ListItem.TABLE_NAME,
            ListItemSuggestion.COLUMN_NAME,
            ListItem.COLUMN_NAME,
            ListItem.COLUMN_NAME,
            ListItemSuggestion.COLUMN_NAME
        ),
        new String[]{filter}
    );

合同类是:

import android.provider.BaseColumns;

public final class ListItem {

private ListItem(){}

public static class ListItemEntry implements BaseColumns
{
    public static final String TABLE_NAME   = "listItem";
    public static final String COLUMN_DONE  = "done";
    public static final String COLUMN_NAME  = "name";
    public static final String COLUMN_COUNT = "count";
    public static final String COLUMN_TIMESTAMP = "timestamp";
}

}

import android.provider.BaseColumns;

public final class ListItemSuggestion {

private ListItemSuggestion(){}

public static class ListItemSuggestionEntry implements BaseColumns
{
    public static final String TABLE_NAME   = "listItemSuggestion";
    public static final String COLUMN_NAME  = "name";
}
}

我得到的错误是:

无法在索引 1 处绑定参数,因为索引超出范围。该语句有 0 个参数。 (这意味着它没有在查询中找到“?”,对吗?虽然有一个......,顺便说一句 "filter" 是一个方法参数)

顺便说一句:该查询的目的是为列表项动态的输入提供建议(= 在 list/table 上,它们可以随时从中删除),同时每个项目也会静默创建建议项目(在另一个 table 中)在实际项目被删除时不会被删除。 where 子句应获取与当前文本输入状态匹配的建议,并排除已在列表中的项目。

不知道你怎么看:

'%%?%%'

可以,但您必须将其更改为串联 '%' || ? || '%':

getReadableDatabase().rawQuery(
        String.format("SELECT lis.%s from %s lis LEFT JOIN %s li ON lis.%s = li.%s WHERE li.%s is NULL AND lis.%s LIKE '%' || ? || '%';",
            ListItemSuggestion.COLUMN_NAME,
            ListItemSuggestion.TABLE_NAME,
            ListItem.TABLE_NAME,
            ListItemSuggestion.COLUMN_NAME,
            ListItem.COLUMN_NAME,
            ListItem.COLUMN_NAME,
            ListItemSuggestion.COLUMN_NAME
        ),
        new String[]{filter}
    );

Cannot bind argument at index 1 because the index is out of range. The statement has 0 parameters. (Meaning its not finding the "?" in the query, right?

不完全是。

though there is one..., btw "filter" is a method argument)

问题是问号在带引号的字符串内。这使它成为纯文本,而不是参数占位符。这种变体似乎是您要找的:

getReadableDatabase().rawQuery(
        String.format("SELECT lis.%s from %s lis LEFT JOIN %s li ON lis.%s = li.%s WHERE li.%s is NULL AND lis.%s LIKE ?;",
            ListItemSuggestion.COLUMN_NAME,
            ListItemSuggestion.TABLE_NAME,
            ListItem.TABLE_NAME,
            ListItemSuggestion.COLUMN_NAME,
            ListItem.COLUMN_NAME,
            ListItem.COLUMN_NAME,
            ListItemSuggestion.COLUMN_NAME
        ),
        new String[]{ "%" + filter + "%" }
    );

完全不相关,但是如果您使用字符串连接,SQL 会更容易阅读:

getReadableDatabase().rawQuery(
        "SELECT lis." + ListItemSuggestion.COLUMN_NAME +
         " FROM " + ListItemSuggestion.TABLE_NAME + " lis" +
         " LEFT JOIN " + ListItem.TABLE_NAME + " li" +
           " ON li." + ListItem.COLUMN_NAME + " = lis." + ListItemSuggestion.COLUMN_NAME +
        " WHERE li." + ListItem.COLUMN_NAME + " IS NULL" +
          " AND lis." + ListItemSuggestion.COLUMN_NAME + " LIKE ?",
        new String[] { "%" + filter + "%" }
    );

实际上,您只使用 li 进行存在性检查,所以这样写:

getReadableDatabase().rawQuery(
        "SELECT " + ListItemSuggestion.COLUMN_NAME +
         " FROM " + ListItemSuggestion.TABLE_NAME +
        " WHERE " + ListItemSuggestion.COLUMN_NAME + " LIKE ?" +
          " AND " + ListItemSuggestion.COLUMN_NAME + " NOT IN (" +
                 " SELECT li." + ListItem.COLUMN_NAME +
                   " FROM " + ListItem.TABLE_NAME + " li )",
        new String[] { "%" + filter + "%" }
    );