SQL LIKE 查询:转义通配符
SQL LIKE query: escape wildcards
我有一个 LIKE 查询 运行 在 Android Uri
的列上,格式如下:
- content://com.android.externalstorage.documents/tree/0000-0000%3A_Issues/document/0000-0000%3A_Issues%2F父母B
- content://com.android.externalstorage.documents/tree/0000-0000%3A_Issues/document/0000-0000%3A_Issues%2F家长A
- 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%';
- 如果我转义 '%':
%_Issues\%2FParentB%'
我没有得到任何结果。
- 如果我不逃走:
'%_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
我有一个 LIKE 查询 运行 在 Android Uri
的列上,格式如下:
- content://com.android.externalstorage.documents/tree/0000-0000%3A_Issues/document/0000-0000%3A_Issues%2F父母B
- content://com.android.externalstorage.documents/tree/0000-0000%3A_Issues/document/0000-0000%3A_Issues%2F家长A
- 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%';
- 如果我转义 '%':
%_Issues\%2FParentB%'
我没有得到任何结果。
- 如果我不逃走:
'%_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