i am trying to union multiple queries but one of the query uses sum() when i try to apply concat on this column i get undesired (blob ? ) result how can i apply concat and union on aggregated column.
i was expecting this result
SELECT "row 1" col1 UNION SELECT concat((5),"%");
returns
# col1
'row 1'
'5%'
but
SELECT "row 1" col1 UNION SELECT concat(sum(5),"%");
returns 'blob' result below
# col1
?
?
how can i apply the concat()in summd column result .
This is a special case for CONCAT, because you have included the SUM(5) expression in its raw form which will always return a numeric value, the CONCAT result will be a binary string. To fix this, simply CAST the numeric expression elements to CHAR first: http://sqlfiddle.com/#!9/9eecb/319356
SELECT "row 1" col1 UNION SELECT concat(CAST(sum(5) as CHAR),"%");
You can also rely on implicit conversion instead of CONCAT for the same result:
SELECT "row 1" col1 UNION SELECT sum(5) + "%";
col1
row 1
5%
MySQL: CONCAT Function
If expression is a numeric value, it will be converted by the CONCAT function to a binary string.
If all expressions are nonbinary strings, the CONCAT function will return a nonbinary string.
If any of the expressions is a binary string, the CONCAT function will return a binary string.
If any of the expressions is a NULL, the CONCAT function will return a NULL value.
You can prove this with a very simple query: http://sqlfiddle.com/#!9/9eecb/319354
SELECT CONCAT(COUNT(*))
Results in:
MQ==
But then if you CAST it to CHAR the response is readable: http://sqlfiddle.com/#!9/9eecb/319355
SELECT CONCAT(CAST(COUNT(*) AS CHAR))
Results:
1
Now what really bakes your noodle is Why did it work in the first query?
In MySQL (and many other databases) most cases a numeric-type constant/literal is automatically coerced to the most appropriate type depending on context. When necessary, you can force a numeric value to be interpreted as a specific data type by casting it explicitly.
The reverse is also true, a string literal that represents a number will often be coerced into the appropriate numeric type.
The most common scenario where we tend to abuse coercion is when using Date or DateTime literals in expressions, the string literal notation is the simplest way to get the value in.
This is a feature of the engine that parses your query, not of the execution. So if you use a parameterized query or you are referencing column values, this coercion does not occur. For the cast of concat((5),"%") the 5 is coerced to a string '5'. For sum(5) the 5 is interpreted as an integer.
12.3 Type Conversion in Expression Evaluation
When an operator is used with operands of different types, type conversion occurs to make the operands compatible. Some conversions occur implicitly. For example, MySQL automatically converts strings to numbers as necessary, and vice versa.
Finally, in regard to UNION, MySQL will attempt to convert the results of associated columns to the type that can natively represent the values from all of the queries:
13.2.9.3 UNION Clause
If the data types of corresponding SELECT columns do not match, the types and lengths of the columns in the UNION result take into account the values retrieved by all the SELECT statements.
A final special case in response to a comment by #forpas
As a workaround use: SELECT "row 1" col1 UNION SELECT concat(sum(5) + 0, "%");
The reason that sum(5) + 0 works is probably better described by using CONCAT(CAST(SUM(5) as SIGNED)+CAST(SUM(0) as SIGNED), "%") which is almost specific. MySQL evaluates each sub-expression individually, but Similar to UNION it considers all the type information of the inputs and outputs at the specific context of the expression. So in this case it is the + operator that tricks the engine into re-checking all the type information in the current context to determine the most appropriate type.
This behaviour is a reason why you might choose to use, or avoid CONCAT for non-strings in the first place in MySQL and just used this expression: SELECT sum(5) + "%";
SELECT concat(5,"%")
, concat(SUM(5), "%")
, concat(SUM(5)+0, "%")
,5+"%"
,concat(SUM(5)+SUM(0), "%")
,CONCAT(CAST(SUM(5) as SIGNED)+CAST(SUM(0) as SIGNED), "%")
;
Fiddle: http://sqlfiddle.com/#!9/9eecb/319381
concat(5,"%")
concat(SUM(5), "%")
concat(SUM(5)+0, "%")
5+"%"
concat(SUM(5)+SUM(0), "%")
CONCAT(CAST(SUM(5) as SIGNED)+CAST(SUM(0) as SIGNED), "%")
5%
NSU=
5%
5
5%
5%
Related
I have complex SQL-Statements with group_concat and i need sometimes to convert the value. So i use something like this (Its an example):
SELECT IF(1=1,CAST(TEST AS CHAR),CAST(TEST AS UNSIGNED))
FROM(
SELECT '40' as TEST
UNION
SELECT '5' as TEST
UNION
SELECT '60' as TEST
) as t1
ORDER BY TEST ASC;
Should return CHAR, returns CHAR.
SELECT IF(1=0,CAST(TEST AS CHAR),CAST(TEST AS UNSIGNED))
FROM(
SELECT '40' as TEST
UNION
SELECT '5' as TEST
UNION
SELECT '60' as TEST
) as t1
ORDER BY TEST ASC;
Should return UNSIGNED, returns CHAR
So the result of IF condition is always a CHAR and need to be CAST.
How i can resolve the problem?
MySQL tries to figure out the column type just by parsing the SQL, not based on runtime conditions like the way an IF() expression goes. While your example allows the result of the IF() to be determined before actually processing any rows, this is not true in general and MySQL doesn't perform this optimization.
It just sees that the IF() can return either UNSIGNED or CHAR, and figures out a common type that both can be converted to safely. This is CHAR.
This is explained in the documentation:
The default return type of IF() (which may matter when it is stored into a temporary table) is calculated as follows:
If expr2 or expr3 produce a string, the result is a string.
If expr2 and expr3 are both strings, the result is case-sensitive if either string is case sensitive.
If expr2 or expr3 produce a floating-point value, the result is a floating-point value.
If expr2 or expr3 produce an integer, the result is an integer.
Examples:
SELECT *
FROM table t
WHERE t.col1
SELECT *
FROM table t
WHERE t.col1 AND t.col2
Depending the nature of the column these queries behaves differently. In my tests, if the column is of the type integer wont show rows with 0s or nulls for that column, if it string, the query will give no result.
I'd like to understand what these types of where conditions mean. Couldn't find any specification for this in the MySQL manual nor an explanation online.
Thanks.
In your query you are not assigning a valid comparision in the where clause (eg: where t.col1 = 10) .. so the where condtion try to eval a casting for the value in the columns mentioned as boolen
in this case the diffent result is just based on the different casting in boolean of each type
if you firts query based on a integer return always a valid true result so yoi get all the rows in the others with string depending of each string value this can produce no rows ,, partial rows or all rows .. try look at the result for the cast of your column in boolean
SELECT if(t.col1, true, false)
FROM table t
WHERE t.col1
and
SELECT if( t.col1 AND t.col2, true,false)
FROM table t
WHERE t.col1 AND t.col2
Those just aren't proper boolean expressions. Boolean expressions evaluate to either true or false and are of the form where t.col1 = 0 and t.col2 >= 3 for example.
The fact that your statements sometimes return data and sometimes not is due to the fact, that 0 and 1 stands for false and true respectively.
Like you already observed, 0 and NULLs don't return rows because they are treated as false in case of 0 and not comparable in case of NULL. Strings on the other hand are implicitly converted to numbers. If the string starts with a number other than 0, the string is converted to that number in MySQL. If the string starts with anything other than that, it's converted to 0. That's why you don't get results for strings.
I would recommend to not use these "short hand boolean expressions". Always write proper expressions!
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
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'.
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