SQL LIKE 查询:转义通配符

SQL LIKE query: escape wildcards

我有一个 LIKE 查询 运行 在 Android Uri 的列上,格式如下:

  1. content://com.android.externalstorage.documents/tree/0000-0000%3A_Issues/document/0000-0000%3A_Issues%2F父母B
  2. content://com.android.externalstorage.documents/tree/0000-0000%3A_Issues/document/0000-0000%3A_Issues%2F家长A
  3. content://com.android.externalstorage.documents/tree/0000-0000%3A_Issues/document/0000-0000%3A_Issues%2F父母A%2F父母B

这些对应于这个文件树:

_Issues
|-ParentA
   |-ParentB
|-ParentB

我尝试了各种避开通配符的手动查询,但我似乎无法获得合适的匹配。为了测试,我将其简化为:

select name from meta where parent LIKE '%_Issues%2FParentB%';
  1. 如果我转义 '%':

%_Issues\%2FParentB%'

我没有得到任何结果。

  1. 如果我不逃走:

'%_Issues%2FParentB%'

我同时匹配浅层 ParentB(需要)和嵌套 ParentB(不需要)。我知道那是因为我允许 Issues 和 ParentB 之间的任何内容都带有 %。

我不明白为什么查询 1 没有结果。我错过了什么?


更新

select name from meta where parent LIKE '%_Issues_2FParentB%';

有效,请注意“_”,因此“\”显然没有转义此数据库。按照@GordonLinoff 的建议明确说明转义字符在我的计算机上有效:

select name from meta where parent LIKE '%_Issues\%2FParentB%' escape '\';

现在想想我们如何在 Android...

中完成同样的事情

是的。最简单的方法是使用 =,如果合适的话。

否则,LIKE 语法包含转义字符。在你的例子中,$ 没有出现在任何地方,所以你可以这样做:

where x like replace(y, '%', '$%') escape '$'

我相信在所有的数据库中,默认是\,所以你也可以这样做:

where x like replace(y, '%', '\%') 

不过,我更喜欢使用 escape 关键字,这样意图就很明确了。

为了扩展@GordonLinoff 的回答,下面是我在 Android 中的具体做法,因为它稍微复杂一些:

/***
 * Creates a LIKE selection statement with all of the given arguments
 * @param column column to select on
 * @param likes array of arguments to select on
 * @param selectionArgs out: formatted arguments to pass to query
 * @param joiner joiner between individual LIKE
 * @param NOT true to set NOT LIKE for all selection arguments
 * @param argStart set a wildcard before every selection argument
 * @param argEnd set a wildcard after every selection argument
 * @return selection statement to query
 */
public static String createLike(String column, String[] likes, List<String> selectionArgs,
                                String joiner, boolean NOT,
                                @Nullable String argStart, @Nullable String argEnd,
                                @Nullable String escapeChar)
{
    StringBuilder selection = new StringBuilder();
    for (int i = 0; i < likes.length; i++)
    {
        if (i > 0) selection.append(joiner);

        if (argStart == null)
            argStart = "";
        if (argEnd == null)
            argEnd = "";

        selection.append(column)
                .append(NOT ? " NOT LIKE ?" : " LIKE ?");

        if (escapeChar != null)
            selection.append(" ESCAPE '\'");

        String argument = likes[i];
        if (escapeChar != null)
            argument = argument.replace(escapeChar, "\" + escapeChar);
        argument = argStart + argument + argEnd;
        selectionArgs.add(argument);
    }

    return selection.toString();
}

并调用:

DbUtil.createLike(Meta.PARENT,
                    filter.hiddenFolders.toArray(new String[filter.hiddenFolders.size()]),
                    selectionArgs,
                    AND,    // Requires AND so multiple hides don't negate each other
                    true,   // NOT
                    null,   // No wild to start, matches path exactly
                    "%",    // Wildcard end to match all children
                    "%"));  // Uri contain '%' which means match any so escape them