MySQL find_in_set with multiple search string
Asked Answered
T

8

61

I find that find_in_set only search by a single string :-

find_in_set('a', 'a,b,c,d')

In the above example, 'a' is the only string used for search.

Is there any way to use find_in_set kind of functionality and search by multiple strings, like :-

find_in_set('a,b,c', 'a,b,c,d')

In the above example, I want to search by three strings 'a,b,c'.

One way I see is using 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')

Is there any other way than this?

Transcend answered 16/2, 2011 at 10:42 Comment(0)
I
134

there is no native function to do it, but you can achieve your aim using following trick

WHERE CONCAT(",", `setcolumn`, ",") REGEXP ",(val1|val2|val3),"
Inn answered 4/10, 2014 at 17:27 Comment(7)
And for rails it works as Model.where('CONCAT(",", setcolumn, ",") REGEXP ?', [val1,val2,val3].join('|'))Hathor
What if my val1|val2|val3 are not in order as the DB entries.Slavish
Amazing answer! - saves me seconds on my query replacing the find_in_set You can eve do this for 2 tables T1 and T2: .... where CONCAT(",", T1.setcolumn, ",") REGEXP CONCAT(",(", REPLACE(T2.setcolumn, ',', '|'), "),")Cianca
Hi, this is working in Mysql. But in PHP i added same. its throwing error for "syntax error, unexpected ',' in Line"Restrained
@AbijithAjayan I've solved same problem with adding Allow User Variables=true in the connection stringAstor
This works great, saved me from stucking in Waiting for table lock and Copying to tmp table freezes...Though, i use it at product filtering and OR is not so good for "filtering"..Any idea how i could use the optimisation for "AND"..before i was using JOIN for each and every Option selected, which resulted in 5-7 different JOINs in same table for different FIND_IN_SET (optionid, "in optionids")...Raki
Nice solution, but I found it to be significantly slower than concatenating FIND_IN_SET with ORHanselka
E
16

The MySQL function find_in_set() can search only for one string in a set of strings.

The first argument is a string, so there is no way to make it parse your comma separated string into strings (you can't use commas in SET elements at all!). The second argument is a SET, which in turn is represented by a comma separated string hence your wish to find_in_set('a,b,c', 'a,b,c,d') which works fine, but it surely can't find a string 'a,b,c' in any SET by definition - it contains commas.

Ejector answered 21/2, 2011 at 20:13 Comment(1)
Yes, you are right. I think The only solution for my problem will be using OR and finset. Like "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')".Transcend
T
2

You can also use this custom function

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
Tucker answered 14/1, 2016 at 14:56 Comment(0)
E
1

Wow, I'm surprised no one ever mentioned this here.
In a nutshell, If you know the order of your members, then just query in a single bitwise operation.

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

Explanation:

If we had a set that has members in this order: "HTML", "CSS", "PHP", "JS"... etc.
That's how they're interpreted in MySQL:

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

So for example, if you want to query all rows that have "HTML" and "CSS" in their sets, then you'll write

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

Because 0011 is 3 which is both 0001 "HTML" and 0010 "CSS".

Your sets can still be queried using the other methods like REGEXP , LIKE, FIND_IN_SET(), and so on. Use whatever you need.

Episodic answered 16/2, 2022 at 22:2 Comment(0)
D
0

Amazing answer by @Pavel Perminov! - And also nice comment by @doru for dynamically check..

From there what I have made for PHP code CONCAT(',','" . $country_lang_id . "', ',') REGEXP CONCAT(',(', REPLACE(YourColumnName, ',', '|'), '),') this below query may be useful for someone who is looking for ready code for PHP.

$country_lang_id = "1,2";

$sql = "select a.* from tablename a where CONCAT(',','" . $country_lang_id . "', ',') REGEXP CONCAT(',(', REPLACE(a.country_lang_id, ',', '|'), '),') ";
Dovev answered 23/12, 2020 at 10:36 Comment(0)
M
0

If you want to match all values instead of OR you should use AND

FIND_IN_SET('a', 'a,b,c,d') > 0 AND FIND_IN_SET('b', 'a,b,c,d') > 0 AND FIND_IN_SET('c', 'a,b,c,d') > 0

In my case SELECT * FROM images WHERE (FIND_IN_SET('illustration', tags) > 0 AND FIND_IN_SET('creative', tags) > 0 AND FIND_IN_SET('design', tags) > 0 AND FIND_IN_SET('drawing', tags) > 0);

Moffat answered 3/5 at 2:10 Comment(0)
A
-4

You can also use the like command for instance:

where setcolumn like '%a,b%'

or

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

which might work in some situations.

Adopted answered 15/10, 2013 at 20:1 Comment(1)
how can you use [where 'a,b,c,d' like '%b,c%'] it may be 'c,b' also. So I think it's not the good solution!Argilliferous
G
-10

you can use in to find match values from two values

SELECT * FROM table WHERE  myvals in (a,b,c,d)
Goggin answered 20/2, 2017 at 6:27 Comment(1)
IN clause does not take a variable. It uses the column w3resource.com/sql/in-operator/sql-in-operator.phpCoolie

© 2022 - 2024 — McMap. All rights reserved.