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
Related
I am running a query on a column postal (type double).
SELECT * FROM `table` WHERE `postal` LIKE 'abcdef'; # returns 1 record
and the same query using = returns 100+ records.
SELECT * FROM `table` WHERE `postal` = 'abcdef'; # returns 107 record
What could be the reason?
You are using LIKE on a DOUBLE field, you should not do that.
LIKE is reserved for pattern matching on strings. Use = for numbers, or convert your digit to a string first using CONVERT and then apply the logic with LIKE.
= compares two values for identity.
LIKE is for pattern matching ie. that is, it matches a string value against a pattern string containing wild-card characters.
Refer here
LIKE will check and return similar values where as = will check for the exact value.
The following things affects the result (not the complete list!)
Implicit conversation
MySQL extension to standard SQL's LIKE operator
In each cases an implicit conversion occours: MySQL tries to convert the values to a common data type. In the first case case 'abcdef' will be converted to double which results to 0. This is why you get 107 records when comparing with equals (=).
SELECT * FROM `table` WHERE `postal` = 'abcdef'; # returns 107 record
You should get exactly the same result by running
SELECT * FROM `table` WHERE `postal` = 0;
In MySQL, LIKE is permitted on numeric expressions. (This is an extension to the standard SQL LIKE.)
This means that SELECT CASE WHEN 10 LIKE '1%' THEN 1 ELSE 0 END is allowed and results to 1 (matched)
To be honest, I'm not sure which double value could match with LIKE operator with the pattern 'abcdef'.
This case is similar to: S.O Question; mySQL returns all rows when field=0, and the Accepted answer was a very simple trick, to souround the ZERO with single quotes
FROM:
SELECT * FROM table WHERE email=0
TO:
SELECT * FROM table WHERE email='0'
However, my case is slightly different in that my Query is something like:
SELECT * FROM table WHERE email=(
SELECT my_column_value FROM myTable WHERE my_column_value=0 AND user_id =15 LIMIT 1 )
Which in a sense, becomes like simply saying: SELECT * FROM table WHERE email=0, but now with a Second Query.
PLEASE NOTE: It is a MUST that I use the SECOND QUERY.
When I tried: SELECT * FROM table WHERE email='( SELECT my_column_value FROM myTable WHERE my_column_value=0 LIMIT 1 )' (Notice the Single Quotes on the second query)
MySql SCREAMED Errors near '(.
How can this be achieved
Any Suggestion is highly honored
EDIT1: For a visual perspective of the Query
See the STEN_TB here: http://snag.gy/Rq8dq.jpg
Now, the main aim is to get the sten_h where rawscore_h = 0;
The CURRENT QUERY as a whole.
SELECT sten_h
FROM sten_tb
WHERE rawscore_h = (
SELECT `for_print_stens_rowscore`
FROM `for_print_stens_tb`
WHERE `for_print_stens_student_id` =3
AND `for_print_stens_factor_name` = 'Factor H' )
The result of the Second Query can be any number including ZERO.
Any number from >=1 Works and returns a single corresponding value from sten_h. Only =0 does not Work, it returns all rows
That's the issue.
CORRECT ANSWER OR SOLUTION FOR THIS
Just in case someone ends up in this paradox, the Accepted answer has it all.
SEE STEN_TB: http://snag.gy/Rq8dq.jpg
SEE The desired Query result here: http://snag.gy/wa4yA.jpg
I believe your issue is with implicit datatype conversions. You can make those datatype conversions explicit, to gain control.
(The "trick" with wrapping a literal 0 in single quotes, that makes the literal a string literal, rather than a numeric.)
In the more general case, you can use a CAST or CONVERT function to explicitly specify a datatype conversion. You can use an expression in place of a column name, wherever you need to...
For example, to get the value returned by my_column_value to match the datatype of the email column, assuming email is character type, something like:
... email = (SELECT CONVERT(my_column_value,CHAR(255)) FROM myTable WHERE ...
or, to get the a literal integer value to be a string value:
... FROM myTable WHERE my_column_value = CONVERT(0,CHAR(30)) ...
If email and my_column_value are just indicating true or false then they should almost certainly be both BIT NOT NULL or other two-value type that your schema uses for booleans. (Your ORM may use a particular one.) Casting is frequently a hack made necessary by a poor design.
If it should be a particular user then you shouldn't use LIMIT because tables are unordered and that doesn't return a particular user. Explain in your question what your query is supposed to return including exactly what you mean by "15th".
(Having all those similar columns is bad design: rawscore_a, sten_a, rawscore_b, sten_b,... . Use a table with two columns: rawscore, sten.)
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
I have an events table with a field called breaks. This is populated with data in a comma separated format, i.e. 1,2,3 or 1 or 1,4,5 - the same format that MySQL's IN command uses.
I'd then like to run a query - on the slots table - to return all rows apart from those specified in events.breaks.
The query, theoretically, should be something like this:
SELECT
`slots`.`id` AS id,
RIGHT(`slots`.`time`, 8) AS `time`
FROM
`slots`, `event`
WHERE
`slots`.`id` NOT IN (`event`.`breaks`)
But that doesn't appear to work - if event.breaks is 4,5,7, the only row from the slots table that doesn't return is 4!
SQLFiddle here: http://sqlfiddle.com/#!2/913fe/1/0
You're passing a single field to the NOT IN () clause, not a subexpression. Think of it like this
(1, 2, 3)
is roughly the same as
SELECT 1
UNION
SELECT 2
UNION
SELECT 3;
as a subexpression. What you're doing instead is
('4,5,7')
which is roughly equivalent to
SELECT '4,5,7';
which in turn MySQL probably converted to a number for the comparison and the result is
NOT IN (4)
What you're actually trying to do isn't really supposed to be done like that. It'd be better if you added an AxB relation table so you can select several rows with the IDs you don't want.
Give this a try:
SELECT slots.id AS id, RIGHT(slots.time, 8) time
FROM slots, event
WHERE FIND_IN_SET(slots.id, event.breaks) = 0
This is how the FIND_IN_SET(str,strlist) function works:
Returns a value in the range of 1 to N if the string str is in the string list strlist consisting of N substrings. A string list is a string composed of substrings separated by “,” characters. [...] Returns 0 if str is not in strlist or if strlist is the empty string.
Also note that IN (val1, val2, val3) is NOT the same as IN (val4) where val4 is a commma-separated string. The IN clause will compare by equality.
you may need a subselect to return the split string
... NOT IN (SELECT your_split_fnc(`event`.`breaks`) FROM `events`)
See answers here for a way to split strings in MySQL Can Mysql Split a column?
instr() MySQL function could be of help also
... INSTR(event.breaks,id) = 0
http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_instr
What I'm Using: The most recent MySQL on Ubuntu 12.
The Set Up: Suppose I have a table "EmployeePayment" with "Name" and "Hours" for each employee. Suppose I already have it populated with values.
The Question: When I use the command
select * from EmployeePayment where Name in ('');
I get the empty set, as I'd expect. But, when I use
select * from EmployeePayment where Name in ('' or '');
I get the entire table returned. Moreover, if I'm picky and put in the command
select Name, SUM(Hours) from EmployeePayment where Name in ('' or '');
then it only returns whatever is the top name from the table. What's happening with this "in" command?
First off, you need to get rid of the or, the proper syntax for the in clause uses commas to separate the possibilities, such as:
sql> select name from people where status in ('intelligent', 'good looking')
pax
1 row returned
What your current variant is doing is applying the or operator to give you a one-element in-list. See here for more detail.
The reason why you're only getting one row for the aggregated query is because you have no group by clause, so you're grouping all rows. Most DBMS' would then complain about having a non-aggregated column that isn't part of the grouping, but MySQL is a bit fancy-free and footloose with the rules in that regard.
It's obviously grouping over the whole table (as it should) but applying some default aggregating function to the name (which it probably shouldn't, but does according to its documentation).
This MySQL extension is covered here but heed the warning: MySQL can choose any of the myriad possible values for these non-aggregated, non-group-by columns, so it's more useful when you know that all the rows in a given group share the same value for the column.
You're effectively doing this:
select * from EmployeePayment where Name in (0);
The OR expression evaluates to 0, and WHERE Name IN (0); returns all rows. You have to use the proper IN syntax as suggested in the other answers:
SELECT * FROM EmployeePayment WHERE Name IN ('foo', 'bar');
IN uses comma separated values, for example: WHERE Name IN ('tim','beth')
So try WHERE Name IN ('','');
But more importantly, why would you want to check where a value is empty or empty? Or was that just to get the question across?
http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_in