I have the follwing simple MySQL query that returns 0 results:
SELECT d.name FROM document d WHERE 10 IN (d.categories)
"categories" is of type varchar and contains for example "10,20,30".
When I type the IN values directly it works and returns a result:
SELECT d.name FROM document d WHERE 10 IN (10,20,30)
I suspect MySQL substitutes d.documents with something like this which of course is not what I want:
SELECT d.name FROM document d WHERE 10 IN ("10,20,30")
What is a proper workaround for this?
When you are providing the value as "10,20,30" then it is treated as a single value as against your expected three distinct values. To make the value as three distinct values you need to use the find_in_set function in MySQL.
Also I would suggest you to go through this thread: Is storing a delimited list in a database column really that bad?
Yes with find_in_set :
SELECT d.name FROM document d WHERE find_in_set(10, d.categories) > 0
Related
I have a string for example 'p2p3p4p9c5c6c7' I want to make a select-statement in mysql that returns how much of those strings ('p6','p7','p8' or 'p9') are containing in the initial string.
The result of my example should be 1, because only 'p9' is containing in my string.
I don't find a good way to do that. Can someone help?
another example
'k2p4p6p8p9c8' the result should be here 3
You would seem to have a poor data format. If you want to store lists of things, use a junction table.
However, the best answer that I can think of is a set of conditions that are added together:
select ((str like '%p6%') +
(str like '%p7%') +
(str like '%p8%') +
(str like '%p9%')
) as NumInString
MySQL treats booleans as integers in a numeric context, with "1" for true and "0" for false.
I should repeat that if the substrings are really codes of some type, then these should be stored in a separate junction table, with one row per code and original row.
SELECT count(*) FROM
(SELECT 'p2p3p4p9c5c6c7' AS a) AS string_table
INNER JOIN
(SELECT 'p6' AS b UNION ALL
SELECT 'p7' UNION ALL
SELECT 'p8' UNION ALL
SELECT 'p9') AS list_table
ON INSTR(string_table.a,list_table.b) > 0;
In a MySQL table i have a field, containing this value for a given record : "1908,2315,2316"
Here is my sql Query :
SELECT * FROM mytable WHERE 2316 IN (myfield)
I got 0 results!
I tried this :
SELECT * FROM mytable WHERE 2315 IN (myfield)
Still 0 results
And then i tried this :
SELECT * FROM mytable WHERE 1908 IN (myfield)
Surprisingly i obtained the record when searching with 1908! What should i do to also obtain the record when searching with 2315 and 2316 ? What am i missing ?
Thanks
You appear to be storing comma delimited values in a field. This is bad, bad, bad. You should be using a junction table, with one row per value.
But, sometimes you are stuck with data in a particular structure. If so, MySQL provides the find_in_set() functions.
SELECT *
FROM mytable
WHERE find_in_set(2316, myfield) > 0;
You can't use IN() over comma separated list of no.s its better to normalize your structure first for now you can use find_in_set to find results matching with comma separated string
SELECT * FROM mytable WHERE find_in_set('1908',myfield) > 0
This question has been asked and answered before, but I don't want to hunt for it; this question should be closed as a duplicate. But, to answer your question:
The commas in the string, the column value, are just characters. Those are part of the string. They aren't seen as "separators" between values in the SQL text. The way SQL sees it, the column contains a single value, not a "list" of values.
So, in your query, the IN (field) is equivalent to an equals comparison. It's equivalent to comparing to a string. For example:
... WHERE 2316 = '1908,2315,2316'
And those aren't equal, so the row isn't returned. The "surprisingly" finding of a match, in the case of:
... WHERE 1908 IN ('1908,2315,2316')
that's explained because that string is being evaluated in a numeric context. That is, the comparison returns true, because all of these also true:
... WHERE 1908 = '1908,2315,2316' + 0
... WHERE 1908 = '1908xyz' + 0
... WHERE 1908 = '1907qrs' + 1
(When evaluated in a numeric context, a string gets converted to numeric. It just happens that the string evaluates to a numeric value that equals the integer value it's being comparing to.)
You may be able to make use of the MySQL FIND_IN_SET function. For example:
... WHERE FIND_IN_SET(2316,'1908,2315,2316')
But, please seriously reconsider the design of storing comma separated list. I recommend Bill Karwin's "SQL Antipatterns" book...
http://www.amazon.com/SQL-Antipatterns-Programming-Pragmatic-Programmers/dp/1934356557
In mysql IN clause is utilized as
SELECT * FROM mytable WHERE column_name IN (set_of_values) ;
Mention column name instead of values
Please try
SELECT * FROM mytable WHERE LOCATE(CONCAT (',', 2316 ','), CONCAT (',',myfield,',' ) ) <>0
In my database table I have 6 Columns id(auto),title,news,image,type
I write this query.
select id,title,image
from add_news
where FIND_IN_SET('Travel','Music',type)
ORDER BY id DESC
I am getting this error
Incorrect parameter count in the call to native function 'FIND_IN_SET'
I am guessing that type is a comma-delimited list. This is a very poor data format, and you should have a separate table with one row per type and article.
But, given the format, the correct syntax is:
select id, title, image
from add_news
where find_in_set('Travel', type) > 0 or
find_in_set('Music', type) > 0
order by id desc;
Use IN operator instead of FIND_IN_SET()
Try this:
SELECT A.id, A.title, A.image
FROM add_news A
WHERE A.type IN ('Travel', 'Music')
ORDER BY A.id DESC
I'm trying to run a SQL SELECT statement against a column that is of type SET. The table is called myTable and the columns in myTable are called base_props and names. The base_props column is of type SET. The values in base_prop are vb,nt, cnt,poss and loc. So I would like to SELECT entries from the column 'name' where base_props have both the values, vb and poss. The results I'm looking to get may have values other than just vb and poss. So to be clear I would like to select all entries that have the values vb and poss regardless if they have other values as well. I've tried the following SQL queries but I can't get the desired results.
SELECT name from myTable WHERE base_props = 'vb' AND base_props = 'poss'
That query returns an empty result set. I've tried using FIND_IN_SET() and IN() but I couldn't get anywhere with that. I've written SQL statements before but never had to deal with columns that are type SET. Any help is appreciated.
The only thing I can come up with is using the LIKE keyword:
SELECT name FROM myTable WHERE (base_props LIKE '%vb%' AND base_props LIKE '%poss%');
This will make sure both vb and cnt are in the base_props column. Of course you can use cnt, nt and loc in there, or any number of base_props values in the sql, just add more AND statements.
OR as a deleted answer by samitha pointed out, you can use FIND_IN_SET:
SELECT name from myTable WHERE FIND_IN_SET('vb', base_props) AND FIND_IN_SET('poss', base_props);
Comment (by spencer7593): "both of these work, but there is a slight difference. The LIKE operator will actually match any member that includes the search string anywhere in a term; the FIND_IN_SET function will only match an exact member. It's also possible to search for members in set by the order they appear in the SET definition, using the MySQL BITAND operator: for example, to match the 1st and 4th members of the set: WHERE base_props & 1 AND base_props & 8". So for example, if you have 'a' and 'aaa' in your set, then using the LIKE "%a%" method will also return rows containing 'aaa'.
Conclusion: use the FIND_IN_SET solution since it will work for all cases.
FIND_IN_SET return index, Try this
SELECT name from myTable WHERE FIND_IN_SET(base_props, 'vb') > 0 AND
FIND_IN_SET(base_props, 'poss') > 0
So I have a data with format like ;1;;2; and then I need to use this number in a query so I thought I'd convert it to 1,2 and use that in a IN condition. In my table, the result should return 2 rows but instead it is returning only 1 row.
My query is like this. The subquery return 1,2 with no problem but only 1 row is retrieve.
select *
from wt_lists
where id IN ((select replace (replace(sendto, ';;',','),';','')
from wt_stats where statsid IN (1)))
But when I try it with this. It returns the correct result, which in my case is 2 rows.
select *
from wt_lists
where id IN (1,2)
What am I missing here?
Comma delimited strings need to be explicitly defined in the query in order to be used in the IN clause - there's countless examples on SO where people need to use dynamic SQL to incorporate user submitted comma delimited strings.
That said, I have a solution using the FIND_IN_SET function:
SELECT DISTINCT wl.*
FROM WT_LISTS wl
JOIN (SELECT REPLACE(REPLACE(ws.sendto, ';;',','),';','') AS ids
FROM WT_STATS ws
WHERE ws.statsid = 1) x ON FIND_IN_SET(wl.id, x.ids) > 0
You are replacing the string:
';1;;2;'
To:
'1,2'
So, you SQL query looks like:
select * from wt_lists where id IN ('1,2') from wt_stats where statsid IN (1)
To use IN clause you need select different values in different rows.
I found this store procedure that does exactly what you need.
http://kedar.nitty-witty.com/blog/mysql-stored-procedure-split-delimited-string-into-rows/
I have not tested, but it is the way.
Obs: Like David said in the comments above, parsing the data in your application is a better way to do this.