FIND_IN_SET 函数在 MySQL 官方文档 中的定义如下:


  • FIND_IN_SET(str, strlist)

    Returns a value in the range of 1 to N if the string str is in the string list strlist consisting of N substrings. A string list is a string composed of substrings separated by , characters. If the first argument is a constant string and the second is a column of type SET, the FIND_IN_SET() function is optimized to use bit arithmetic. Returns 0 if str is not in strlist or if strlist is the empty string. Returns NULL if either argument is NULL. This function does not work properly if the first argument contains a comma (,) character.

大概意思就是,FIND_IN_SET(str, strlist) 函数接受两个参数:

第一个参数 str 是要查找的字符串。第二个参数 strlist 是要搜索的用 ,(英文逗号) 分隔的字符串。

  • 如果 strstrlist 为 NULL,则函数返回 NULL
  • 如果 strlist 中不包含 str,则返回 0
  • 如果 strlist 中包含 str,则返回一个在 1-N 之间的正整数(N 为按照逗号分隔的元素数量),这个整数就表示 strstrlist 中的第几个

需要注意的是,如果 str 中包含了 ,,该函数将无法正常工作(实测返回值为 0,表示没找到)。并且,如果 str 是一个常量字符串,而且 strlist 是一个类型为 SET 的列,MySQL 将会使用使用位算术来优化查找性能。


来自官方的例子:

SELECT FIND_IN_SET('b', 'a,b,c,d') AS result;

查询结果
查询结果

使用起来很简单易懂,在实际项目中用到的地方也有不少,比如最近项目中需要查询一个地区其下的所有子地区,每个地区都有一个 parent_code 字段标记自己的直接父级是谁,还有一个 path_code 字段存储了从最顶级到当前地区的层级 code 字符串,用逗号分隔的。由于地区不是只有两级,所以没法简单又直接的根据 parent_code 字段实现这个需求.通过 LIKE path_code 的形式来模糊查询也不准确,比如我关键词为 1,那 11,111 这种格式的数据都会被查到,这个时候就需要用到 FIND_IN_SET 函数了,就是专门处理这种逗号分隔的字符串搜索的,最终的实现 SQL 如下:

SELECT code, name, path_code
FROM sys_region_info
WHERE FIND_IN_SET(#{regionCode}, path_code);

这里以 #{regionCode} = 26(四川省的 code)为例,查询四川省下的所有子地区,查询出来的结果如下:

部分查询结果截图
部分查询结果截图

由于表的设计,查询结果里是包含了 code = 26 自己的,如果不需要查询出自己的话可以再稍微修改一下这条 SQL 即可:

SELECT code, name, path_code
FROM sys_region_info
WHERE FIND_IN_SET(#{regionCode}, path_code)
AND path_code != #{regionCode}