MySQL list IN list - mysql

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..

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

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

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....

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

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.

Related

MySQL update order (row number) from comma delimited list - the simplest way

I have a table with two columns ID and ORDER, what I want to achieve is to update ORDER column as list numbers (like 1, 2 ...).
I have input as comma-delimited list of IDs:
21545,13117,21538,940,19658,21547,21532,7404,19663,19666,863,13114,13121,11769,13147,13156,972,13165,13174,13182,853,19671,7429,935,1015,931,986,996,991,953,893,920,899,906,20972,886,873,21574,21548
I need to update ORDER so 21545 = 1, 13117 = 2 and so on.
What is the simplest way to achieve this?
Maybe this is an easy task for you, but I am an MSSQL developer, so please don't mind me asking this. Thanks.
You can use the FIELD function to return the position of a value in a set of values if you are building the query from scratch e.g.
SELECT FIELD(13117, 21545,13117,21538,940,19658)
If you have a string which is comma separated, you can use FIND_IN_SET:
SELECT FIND_IN_SET(13117, '21545,13117,21538,940,19658')
In both cases the output is 2.
You can find a demo showing the use of these functions in an UPDATE query on dbfiddle

MySQL Query conditional find nth element in column string

I have a MySQL table setup where one column's values are a string of comma-separated True/False values (1s or 0s). For example, in the column, one field's value may be "0,1,0,0,0,0,1,1,0" and another may be "1,0,0,1,1,1,0,0,0" (note: these are NOT 9 separate columns, but a string in one column). I need to QUERY the MySQL table for elements that are "true"(1) for the "nth element" of that column's value/string.
So, if I was looking for rows, with a specific column, where the 3rd element of the column's value was 1, it would produce a list of results. So, in this case, I would only be searching for "1" in the fth place (12345 = X,X,X...) of the string (X,X,1,X,X,X,X,X,X,X). How can I query this?
This is a crude example of what I am trying to do ...
"SELECT tfcolumn FROM mytable WHERE substr({tfcolumn}, 0, 5)=1"
{tfcolumn} represents the column value
5 represents the 5th position of the string
=1 represents what I need that position to equal to.
Please help. Thanks
You can't. Once you put a serialized data type into a column in SQL (like comma separated lists, or JSON objects) you are preventing yourself from performing any query on the data in those columns. You have to pull the data in a different way and then use a program like python, VB, etc to get the comma separated values you are looking for.
Unless you want to deal with trying to make this mess of a query work...
I would recommend changing your table structure before it's too late. Although it is possible, it is not optimized in a format that a DBMS recognizes. Because of that the DBMS will spend a significant amount of time going through every record to parse the csv values which is something that it was not meant to be doing. Doing the query in SQL will take as much time (if not more time) than just pulling all the records and searching with a tool that can do it properly.
If the column contains values exactly like the ones you posted, then the Nth element is at the 2 * N - 1 position in the comma separated list.
So do this:
SELECT tfcolumn
FROM tablename
WHERE substr(tfcolumn, 2 * 5 - 1, 1) = '1'
Replace 5 with the index that you search for.
See the demo.
Or remove all commas and get the Nth char:
SELECT tfcolumn
FROM tablename
WHERE substr(replace(tfcolumn, ',', ''), 5, 1) = '1'
See the demo.
Try this
if substring_index(substring_index('0,1,0,0,0,0,1,1,0',',',3),',',-1)='1'
The first argument can be your column name. The second argument (',') tells the function that the string is comma-separated. The third argument takes the first 3 elements of the string. So, the output of inner substring_index is '0,1,0'.
The outer substring_index has -1 as the last argment. So, it starts counting in reverse direction & takes only 1 element starting from right.
For example, if the value in a particular row is '2,682,7003,14,185', then the value of substring_index(substring_index('2,682,7003,14,185',',',3),',',-1) is '7003'.

Show Fields but with content

i'm trying to show fields names on a combobox, but I need only those that are not null or have blank spaces.
I all ready have the field names with this query:
SHOW FIELDS FROM model WHERE type LIKE 'varchar(15)'
Any idea about how can i do this?
Update:
I'm working with an old database who is poorly designed. I attached an image:Database Screenshot This is a tire sizes database, so i need to get the years by model who has the size captured to show them in a combo box.
You can use your current query to get the "candidate" fields, but (short of some very complicated dynamic sql) you'll need to build a separate query to determine which candidates are pertinent. Generically, something like:
SELECT SUM(IF(field1 REGEXP '[a-zA-Z0-9.]+', 1, 0) > 0 AS showField1
, SUM(IF(field2 REGEXP '[a-zA-Z0-9.]+', 1, 0) > 0 AS showField2
, ...
FROM theTable
;
Depending on what you consider "has values" the regexp string may need adjusted; learn more here: http://dev.mysql.com/doc/refman/5.7/en/regexp.html
If the table is huge (large number of rows), you may be better off querying on each field separately like this (the one above will be looking at the whole table without some sort of WHERE to reduce the rows examined):
SELECT 1 FROM theTable WHERE fieldX REGEXP '[a-zA-Z0-9.]+' LIMIT 1;
Treating having a query result as "yes" and no result as "no content".

Assigning Each Like Statement A Value That Is Returned On Matching

I have a string array comprised of words (ex. { alpha, beta, gamma } ) and a MySQL table filled with words. For each string array, I come up with a SELECT statement that queries the MySQL table to see if there are any matches of words. The rows that are returned let me know when a word in my string array is one of the unique ones in the table. I then alter the text of the specific string in the string array. For simplicity sake, let's assume I want to call a .ToUpper() on it.
My current method is to get all of the rows from the table that match and then loop through the string array and check whether every single row returned matches every single string in the array. That's incredibly inefficient, and I would much rather have the rows returned from my MySQL query have a column that tells me which position in the string array that word came from. That way I can jump right there and fiddle around with the string. Is there a way to give each "LIKE" clause in the where statement a unique identifier that is returned if that specific like clause is the one that matches? Any ideas would be much appreciated.
My Select Statement is:
SELECT `WordText` FROM `Words` WHERE `WordText` LIKE 'alpha%' OR `WordText` LIKE 'gamma%';
What I am looking for is something like this:
SELECT `WordText`, PositionInArray FROM `Words` WHERE `WordText` LIKE 'alpha%' (IF MATCH THEN PositionInArray=0 -- alpha's position in my array) OR `WordText` LIKE 'gamma%' (IF MATCH THEN PositionInArray=2 - gamma's position in my array);
When this row is returned, I can go straight to WordArray[PositionInArray].ToUpper() and know that that is the word that matched.
Thanks a lot!
SELECT CASE WHEN WordText LIKE 'alpha%' THEN 0 WHEN WordText LIKE 'beta%' THEN 1
WHEN 'gamma%' THEN 2 ELSE -1 END AS match FROM Words WHERE match <> -1

Extract specific words from text field in mysql

I have a table that contains a text field, there is around 3 to 4 sentences in the field depending on the row.
Now, I am making an auto-complete html object, and I would like to start typing the beginning of a word and that the database return words that start with those letters from the database text field.
Example of a text field: I like fishsticks, fishhat are great too
in my auto-complete if I would type "fish" it would propose "fishsticks" and "fishhat"
Everything works but the query.
I can easily find the rows that contains a specific word but I can't extract only the word, not the full text.
select data_txt from mytable match(data_txt) against('fish', IN BOOLEAN MODE) limit 10
I know it is dirty, but I cannot rearrange the database.
Thank you for your help!
EDIT:
Here's what I got, thanks to Brent Worden, it is not clean but it works:
SELECT DISTINCT
SUBSTRING(data_txt,
LOCATE('great', data_txt),
LOCATE(' ' , data_txt, LOCATE('great', data_txt)) - LOCATE('great', data_txt)
)
FROM mytable WHERE data_txt LIKE '% great%'
LIMIT 10
any idea on how to avoid using the same LOCATE expression over and over?
Use LOCATE to find the occurrence of the word.
Use LOCATE and the previous LOCATE return value to find the occurrence of the first space after the word.
USE SUBSTR and the previous 2 LOCATE return values to extract the whole word.
$tagsql ="SELECT * from mytable";
$tagquery = mysql_query($tagsql);
$tags = array(); //Creates an empty array
while ($tagrow = mysql_fetch_array($tagquery)) {
$tags[] = tagrow['tags']; //Fills the empty array
}
If the rows contain commas you could use -
$comma_separated = implode(",", $tags);
you can replace the comma for spaces if they are separated as spaces in your table.
$exp = explode(",", $comma_separated);
If you require your data to be unique you may include the following:
$uniquetags = array_unique($exp, SORT_REGULAR);
you can use print_r to see the results of the array resulting
Here array_merge is used because $rt will not get displayed if you are using a 'jquery' autocomplete else $rt may work and array_merge can be ignored. However, you may use array_merge to include multiple tables by repeating the previous process.
$autocompletetags = array_merge((array)$uniquetags);
This sorts the values in the alphabetic order
sort($autocompletetags, SORT_REGULAR);