SQL - partially order by list of id's - mysql

I have a table which I query, the condition is something like id >10, and i want to add a condition based on id's from a list something like AND id IN(3,4,5,6,7).
I want to order the results by the id's from the list first.
can it be done?

In case you're using MySQL: (please tag questions appropriately)
From the manual:
FIELD(str,str1,str2,str3,...)
Returns the index (position) of str in the str1, str2, str3, ... list. Returns 0 if str is not found.
If all arguments to FIELD() are strings, all arguments are compared as strings. If all arguments are numbers, they are compared as numbers. Otherwise, the arguments are compared as double.
If str is NULL, the return value is 0 because NULL fails equality comparison with any value. FIELD() is the complement of ELT().
mysql> SELECT FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo');
-> 2
mysql> SELECT FIELD('fo', 'Hej', 'ej', 'Heja', 'hej', 'foo');
-> 0
So you can easily do
SELECT
...
ORDER BY FIELD(id, 3,4,5,6,7), id

Related

SELECT * FROM tableName WHERE 'num+sometext'

I am curious to know , how these queries work in database engine. Specially my focus is on line no 4 and 6.
1.SELECT * FROM tableName
2.SELECT * FROM tableName WHERE 1
3.SELECT * FROM tableName WHERE 123
4.SELECT * FROM tableName WHERE '2xyz'
5.SELECT * FROM tableName WHERE ''
6.SELECT * FROM tableName WHERE 'xyz'
In the above queries 1,2,3,4 are producing same result but 5 and 6 are not producing any result. why? what is diff b/w WHERE '2xyx' and 'xyz'?
How '2xyz' implicitly converted into 2 ?
The where clause evaluates to boolean true (not 0) or false (0) in order to decide if a record is in or out of the resultset.
Cases 2 and 3 retrive all records because the non zero numbers evaluate to true.
Case 3 retrieves all records because during the implicit string to number conversion mysql evaluates the string from left to right character by character. As long as as the characters can be evaluated as a number, mysql will take their value. This includes chopping of leading spaces, interpreting plus or minus signs, decimal points, and so on. So, the string '2xyx' is interpreted as 2, thus boolean true.
Case 4 and 5 do not retrieve any records because the strings' leftmost character cannot be evaluated as a number, so the conversion returns 0, thus boolean false.
Unfortunately, the implicit string to number conversion is not really documented in the MySQL manual. Most of the rules, however, can be deducted from the following part in Type Conversion in Expression Evaluation section of the manual:
For comparisons of a string column with a number, MySQL cannot use an
index on the column to look up the value quickly. If str_col is an
indexed string column, the index cannot be used when performing the
lookup in the following statement:
SELECT * FROM tbl_name WHERE str_col=1;1
The reason for this is that there are many different strings that may
convert to the value 1, such as '1', ' 1', or '1a'.
It is WHERE <condition>, e.g. WHERE col1 = 123. What you have instead is WHERE <number> or WHERE <string>, so there is an expression missing.
What would be possible though is WHERE <boolean>, and this is what MySQL expects. And as MySQL treats booleans like numbers (0 = false, other numbers = true), it looks for a number.
1 and 123 are numbers that result in true.
'2xyz' gets converted to 2, i.e. true.
'' and 'xyz' get converted to 0, i.e. false.
So the latter give you an empty result set as the where condition renders false.
In statement SELECT ... WHERE [where_condition], in where_condition expression you can use any of the functions and operators that MySQL supports, in which string literal is also supported. For strings the comparisons are based on the numeric values of the string unit. When evaluating an expression type conversion is also done.
So in above case the 2xyz gets converted to 2 which is true and hence you get all the records. Its like
SELECT * FROM tableName WHERE 2
and the string xyz gets converted to 0 which is false due to which you get empty result set. Its same as:
SELECT * FROM tableName WHERE 0
Where having condition value. Mysql any number treat as TRUE value and null or '' treat as FALSE.
1.SELECT * FROM tableName -- all record return
2.SELECT * FROM tableName WHERE 1 -- Return true value
3.SELECT * FROM tableName WHERE 123 -- Return true value
4.SELECT * FROM tableName WHERE '2xyz' -- Return true value because there first character is number
5.SELECT * FROM tableName WHERE '' -- false value return
6.SELECT * FROM tableName WHERE 'xyz' -- false value return

What is the difference between = and LIKE

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

MySQL In clause not giving the right result

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

Use comma separated list from one table as clause in query for another table

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

Map integer(id) to text string?

In my database, I'm storing a field called "type" as tinyInt, since I don't have that many types I decided not to create a table for storing the corresponding names of all these types.
When I query my table I want the types to be replaced by their corresponding names which I'm storing in php arrays. I wonder if there is a way to do this replacement inside the sql statement itself instead of looping through the results and do replacement on the returned result row.
Does something like this even exists:
select *, map(type, {1=>'abc', 2 => 'xyz'}) from orders
The only way (I'm fairly sure) to do this is using a CASE .. WHEN ... construct:
SELECT *, CASE type WHEN 1 THEN 'abc' WHEN 2 THEN 'xyz' END as stringType
FROM orders
You can also use the ELSE clause to specify a default, e.g. CASE type WHEN 1 THEN 'abc' WHEN 2 THEN 'xyz' ELSE 'unknown' END.
Actually, in contrast to the answer by mathematical.coffee, there actually is another way in MySQL to map a number to text - at least if your numbers are contiguous:
The ELT() function returns the N-th element of the list of strings: str1 if N = 1, str2 if N = 2, and so on. Returns NULL if N is less than 1 or greater than the number of arguments.
Example:
mysql> SELECT ELT(1, 'ej', 'Heja', 'hej', 'foo');
-> 'ej'
mysql> SELECT ELT(4, 'ej', 'Heja', 'hej', 'foo');
-> 'foo'
Source:
https://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_elt