MySQL find_in_set函数如何查找多个字符串?

61

我发现 find_in_set 只能搜索单个字符串:

find_in_set('a', 'a,b,c,d')
在上面的示例中,'a'是唯一用于搜索的字符串。
是否有任何方法可以使用类似find_in_set的功能并通过多个字符串进行搜索,例如:
find_in_set('a,b,c', 'a,b,c,d')
在上面的例子中,我想通过三个字符串'a,b,c'进行搜索。
我看到的一种方法是使用OR。
find_in_set('a', 'a,b,c,d') OR find_in_set('b', 'a,b,c,d') OR find_in_set('b', 'a,b,c,d')

有没有其他方法?

7个回答

134

没有原生的函数可以完成这个任务,但是您可以使用以下技巧实现您的目标

WHERE CONCAT(",", `setcolumn`, ",") REGEXP ",(val1|val2|val3),"

对于Rails而言,它的工作方式是Model.where('CONCAT(",", setcolumn, ",") REGEXP ?', [val1,val2,val3].join('|'))。 - Alexey
3
如果我的val1|val2|val3不按照数据库条目的顺序排列,会怎样呢? - Harshit
2
惊人的答案! - 让我在查询中替换find_in_set节省了几秒钟。您甚至可以为T1和T2两个表执行此操作:....其中CONCAT(“,”,T1.setcolumn,“,”)REGEXP CONCAT(“,(”,REPLACE(T2.setcolumn,',','|'),”),“)” - doru
嗨,这个在Mysql里是可以工作的。但是在PHP中我加了相同的东西,它抛出了“语法错误,在Line中意外的','”的错误。 - Abijith Ajayan
2
@AbijithAjayan 我通过在连接字符串中添加 Allow User Variables=true 来解决了相同的问题。 - Arash.Zandi
显示剩余2条评论

16

MySQL函数find_in_set()只能在一组字符串中搜索单个字符串。

第一个参数是一个字符串,因此无法将其解析为字符串(您根本无法在SET元素中使用逗号!)。第二个参数是一个SET,由逗号分隔的字符串表示,因此您希望使用find_in_set('a,b,c','a,b,c,d'),它可以工作得很好,但它肯定找不到包含逗号的字符串'a,b,c'在任何SET中 - 它包含逗号。


9
没错,你说得对。我认为解决我的问题的唯一方法是使用OR和finset。就像这样:"find_in_set('a', 'a,b,c,d') OR find_in_set('b', 'a,b,c,d') OR find_in_set('b', 'a,b,c,d')"。 - Mukesh Chapagain

2
您可以使用此自定义函数。
CREATE FUNCTION SPLIT_STR(
  x VARCHAR(255),
  delim VARCHAR(12),
  pos INT
)
RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
       LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
       delim, ''); 

DELIMITER $$
    CREATE FUNCTION `FIND_SET_EQUALS`(`s1` VARCHAR(200), `s2`  VARCHAR(200)) 
    RETURNS TINYINT(1)
    LANGUAGE SQL
    BEGIN
          DECLARE a INT Default 0 ;
            DECLARE isEquals TINYINT(1) Default 0 ;
          DECLARE str VARCHAR(255);
          IF s1 IS NOT NULL AND s2 IS NOT NULL THEN
             simple_loop: LOOP
                 SET a=a+1;
                 SET str= SPLIT_STR(s2,",",a);
                 IF str='' THEN
                    LEAVE simple_loop;
                 END IF;
                 #Do  check is in set
                 IF FIND_IN_SET(str, s1)=0 THEN
                    SET isEquals=0;
                     LEAVE simple_loop;
                 END IF;
                 SET isEquals=1;
            END LOOP simple_loop;
          END IF;
        RETURN isEquals;
    END;
    $$
    DELIMITER ;

SELECT FIND_SET_EQUALS('a,c,b', 'a,b,c')- 1
SELECT FIND_SET_EQUALS('a,c', 'a,b,c')- 0
SELECT FIND_SET_EQUALS(null, 'a,b,c')- 0

1

哇,我很惊讶这里没有人提到过这个。
简而言之,如果你知道你的成员的顺序,那么只需在单个位运算中查询。

SELECT * FROM example_table WHERE (example_set & mbits) = mbits;

说明:

如果我们有一个集合,其中成员的顺序为:"HTML","CSS","PHP","JS"等。
这是它们在MySQL中的解释:

"HTML" = 0001 = 1
"CSS"  = 0010 = 2
"PHP"  = 0100 = 4
"JS"   = 1000 = 16

例如,如果您想查询所有包含“HTML”和“CSS”集合的行,则可以编写以下代码:
SELECT * FROM example_table WHERE (example_set & 3) = 3;

因为00113,它既是0001"HTML",又是0010"CSS"

您仍然可以使用其他方法(例如REGEXP、LIKE、FIND_IN_SET()等)查询您的集合。使用您需要的任何方法。


0

@Pavel Perminov 的回答非常棒!- @doru 的评论也很好,可以动态检查。

从这里开始,我为 PHP 代码做了什么 CONCAT(',','".$country_lang_id."',',')REGEXP CONCAT(',(',REPLACE(YourColumnName,',','|'),'),' 下面的查询可能对正在寻找 PHP 准备代码的人有用。

$country_lang_id = "1,2";

$sql = "select a.* from tablename a where CONCAT(',','" . $country_lang_id . "', ',') REGEXP CONCAT(',(', REPLACE(a.country_lang_id, ',', '|'), '),') ";

-4

你也可以使用 like 命令,例如:

where setcolumn like '%a,b%'

或者

where 'a,b,c,d' like '%b,c%'

在某些情况下可能有效。


1
你如何使用 [where 'a,b,c,d' like '%b,c%'],它也可能是 'c,b'。因此,我认为这不是一个好的解决方案! - FAISAL

-10

你可以使用 in 来从两个值中查找匹配的值

SELECT * FROM table WHERE  myvals in (a,b,c,d)

1
IN子句不接受变量。它使用列http://www.w3resource.com/sql/in-operator/sql-in-operator.php。 - Shahbaz A.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接