15

I currently store user's inputs in comma separated lists like so:

Userid | Options
1      |  1,2,5

A user ticks a set of options in a form which is an array, which is then joined with a comma to make

1,2,5

Then MySQL is trying to find other users who some or all of the same options ticked on a different field name (although same table).

Currently I do this:

WHERE `choices` IN ('.$row['myoptions'].')

So this could be something like:

WHERE 1,2,5,8 IN (1,4,6)

This would return true because theres at least one value match right? Or have i got this confused..

Sir
  • 8,135
  • 17
  • 83
  • 146
  • What is the datatype of the Options? – Starx Dec 02 '11 at 05:29
  • `choices` also have comma separated values or a single value??? – xkeshav Dec 02 '11 at 05:30
  • @Starz datatype is obviously varchar – xkeshav Dec 02 '11 at 05:31
  • you want the exact set of options will be matched or any of the options like your doing here. – Punit Dec 02 '11 at 05:32
  • I think it will return True, ofcourse a tupple or so. – ScoRpion Dec 02 '11 at 05:32
  • You should not be constructing SQL queries like that. Use prepared statements. –  Dec 02 '11 at 05:33
  • @diEcho yes it does :) I provided example on the post :) – Sir Dec 02 '11 at 05:33
  • @NathanHoad there are like 50 + options i can't see a way to normalize the database for it.. unless i make a table with 50+ fields it seemed less practical to my current method =/ – Sir Dec 02 '11 at 05:34
  • I'm sorry, but I fail to see how database normalization relates to using prepared statements. –  Dec 02 '11 at 05:35
  • @Dave you dont need to make table with fifty fields to normalize the table. You just need another table with id, userid, option. just three columns – Zohaib Dec 02 '11 at 05:36
  • @diEcho, `StarZ` is not who i am, and its not obviously vachar, might be SET too, seeing the datastored. Besides, I asked the OP, how are so sure? – Starx Dec 02 '11 at 05:40
  • How would the syntax be if you used a list of numbers to check against a subquery per your suggestion @Zohaib? I am not familiar with prepared statements @Nathan Hoad The fields are VarChar by the way :) – Sir Dec 02 '11 at 05:41
  • @dave `choices` column is in which table??? – xkeshav Dec 02 '11 at 05:45
  • @Starx : sorry that is typo and thank for the information of `set` datatype. I forgot that but actually nobody uses `set` datatype too early.. – xkeshav Dec 02 '11 at 05:46
  • @diEcho that is stored in user table. – Sir Dec 02 '11 at 05:47
  • and `Options` column is are also in same table!! – xkeshav Dec 02 '11 at 05:50
  • Yeh but in the query it self it is stored in a variable and i use that, because its related to the session of user viewing the page. – Sir Dec 02 '11 at 05:52

5 Answers5

27

May be you are going the wrong way to do this.

The function FIND_IN_SET might be helpful if the options column type is SET.

Example:

SELECT * FROM yourtabe WHERE FIND_IN_SET('2', Options);

But, it will only let you compare one string at a time, in the above example, it compares if 2 is present in the rows. If you have to compare multiple values you cannot accomplish that by using FIND_IN_SET.

However, in your case, LIKE clause may be of use to.

May be something like

SELECT * FROM yourtable WHERE Options LIKE '%2,3%';

Now this will search for 2,3 value anywhere in the column, and give the result. But this also comes with another complication, it gives the result only if 2,3 is present side by side of each other, if the column has 2,1,3 or 2,4,5,3 or even 3,2 it will not list these records.

Now coming to your question

`WHERE `choices` IN (1,4,6)`, 

will translate to

WHERE `choices` = '1' OR `choices` = '4' OR `choices` = '6'

so it will return false

Why?

because your column contains not only 1 or 4 or 6 but 1,2,5 as one string. So all the comparisons above to return false

fhugas
  • 392
  • 1
  • 10
Starx
  • 77,474
  • 47
  • 185
  • 261
  • So my IN function is the best option as it will be comparing multiple fields? – Sir Dec 02 '11 at 05:38
  • OMG, i did a mistake, it will return false. I will explain it – Starx Dec 02 '11 at 05:51
  • So it will return false every time if a user tries to search more than one value with IN ? – Sir Dec 02 '11 at 05:53
  • 1
    That's where your datatype will matter the most. As varchar whether you compare single number or multiple only exact match with columns data will return true, if not it will return false. If single comparison is what you want then, `SET` is the best choice you have, see the example i provided. – Starx Dec 02 '11 at 05:57
  • You can see [this](http://stackoverflow.com/questions/5015403/mysql-find-in-set-with-multiple-search-string) previously asked question for extra information – Starx Dec 02 '11 at 05:58
3

I do not think this will return true.

WHERE CHOICES IN ()

when you do this, it will compare complete choices value to individual item inside IN

You might wanna have a look at find_in_Set function of MySQL

WHERE find_in_set(optionNumber1, choices) > 0 
OR find_in_set(optionNumber2, choices) > 0
OR find_in_set(optionNumber3, choices) > 0

You will have to make query in a loop in programming language you are using

Zohaib
  • 7,026
  • 3
  • 26
  • 35
  • Well this why im confused because have been suggesting both functions to me =/ – Sir Dec 02 '11 at 05:35
  • this is simple, no need to be confused, IN() will compare complete String on left Side with comma seperated strings on the right side. You might wanna use find_in_set function, but this way you will have to comapre one option at a time – Zohaib Dec 02 '11 at 05:42
1

I think you are not getting Confused. You are absolutely right this will return something (a tuple or more then one tuple) and that of-course is a True value. So Carry on....

ScoRpion
  • 11,364
  • 24
  • 66
  • 89
0

just had the same problem. solved it using RLIKE:

$options_in_row = array_filter(explode(',',$row['myoptions'])); // convert the csv to array of numbers. use array_filter because empty values will generate a regex that always find something.
$options_rx = implode('|', array_map(function ($x)
        {
            return "\b$x\b"; // adding \b to avoid partial number hits, such as '2' inside '123,234'
        }, $options_in_row));
// $options_rx is something like '\b123\b|\b234\b'
$sql = '.... WHERE `choices` RLIKE "'.$options_rx.'"';

take into account that this code assumes csv of numbers. if your case is different you'll have to add escaping.

oriadam
  • 7,747
  • 2
  • 50
  • 48
0

I don't know where is choice column in which table, but have u tried this way

SELECT * FROM t1 WHERE `choices` > ANY (SELECT options FROM t2);

Reference

xkeshav
  • 53,360
  • 44
  • 177
  • 245
  • Well my query WHERE clause looks like this once compiled: gender IN (2) AND orientation IN (1,2) AND choices IN (1,2,4,5,7,8) The numbers in brackets are from $vars in PHP which were loaded from a row regarding current logged in user which happened to be from same table which were loaded earlier. – Sir Dec 02 '11 at 05:55