Related
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%
condition in below query returning true result but i want false result. Please suggest me.
select *
from test
where
'00160001' between '0013001' and '0023000' OR
'00200000' between '0013001' and '0023000'
You get the same result without the leading zeros.
Use integer data type to compare integer values.
You can also convert the values on the fly using cast:
http://dev.mysql.com/doc/refman/5.7/en/cast-functions.html
Your example with Cast:
select if( cast('00160001' as unsigned) between cast('0013001' as unsigned)
and cast('0023000' as unsigned),1,0) as test_a,
if( cast('00200000' as unsigned) between cast('0013001' as unsigned)
and cast('0023000' as unsigned),1,0) as test_b;
I've a query like this one:
SELECT IF(#param = 42, 'static', SELECT ... );
But it doesn't work because I can't insert a SELECT statement inside a IF(). My problem is that I can't do otherwise (use an if-then statement outside sql) because to "architecture restrictions".
Any solution to select if evaluate or not a query based to parameter value?
You don't need a select:
select (case when #param = 42 then 'static' else date_format(now(), '%Y-%m-%d') end)
Note that you are trying to mix two different types -- a datetime and string. You should explicitly convert the datetime to a string, using your preferred format.
You can write this with if(). case is slightly more general and the ANSI standard.
SELECT IFNULL(NULL, 'Replaces the NULL')
--> Replaces the NULL
SELECT COALESCE(NULL, NULL, 'Replaces the NULL')
--> Replaces the NULL
In both clauses the main difference is argument passing. For IFNULL it's two parameters and for COALESCE it's multiple parameters. So except that, do we have any other difference between these two?
And how it differs in MS SQL?
The main difference between the two is that IFNULL function takes two arguments and returns the first one if it's not NULL or the second if the first one is NULL.
COALESCE function can take two or more parameters and returns the first non-NULL parameter, or NULL if all parameters are null, for example:
SELECT IFNULL('some value', 'some other value');
-> returns 'some value'
SELECT IFNULL(NULL,'some other value');
-> returns 'some other value'
SELECT COALESCE(NULL, 'some other value');
-> returns 'some other value' - equivalent of the IFNULL function
SELECT COALESCE(NULL, 'some value', 'some other value');
-> returns 'some value'
SELECT COALESCE(NULL, NULL, NULL, NULL, 'first non-null value');
-> returns 'first non-null value'
UPDATE: MSSQL does stricter type and parameter checking. Further, it doesn't have IFNULL function but instead ISNULL function, which needs to know the types of the arguments. Therefore:
SELECT ISNULL(NULL, NULL);
-> results in an error
SELECT ISNULL(NULL, CAST(NULL as VARCHAR));
-> returns NULL
Also COALESCE function in MSSQL requires at least one parameter to be non-null, therefore:
SELECT COALESCE(NULL, NULL, NULL, NULL, NULL);
-> results in an error
SELECT COALESCE(NULL, NULL, NULL, NULL, 'first non-null value');
-> returns 'first non-null value'
Pros of COALESCE
COALESCE is SQL-standard function.
While IFNULL is MySQL-specific and its equivalent in MSSQL (ISNULL) is MSSQL-specific.
COALESCE can work with two or more arguments (in fact, it can work with a single argument, but is pretty useless in this case: COALESCE(a)≡a).
While MySQL's IFNULL and MSSQL's ISNULL are limited versions of COALESCE that can work with two arguments only.
Cons of COALESCE
Per Transact SQL documentation, COALESCE is just a syntax sugar for CASE and can evaluate its arguments more that once. In more detail: COALESCE(a1, a2, …, aN)≡CASE WHEN (a1 IS NOT NULL) THEN a1 WHEN (a2 IS NOT NULL) THEN a2 ELSE aN END. This greatly reduces the usefulness of COALESCE in MSSQL.
On the other hand, ISNULL in MSSQL is a normal function and never evaluates its arguments more than once. COALESCE in MySQL and PostgreSQL neither evaluates its arguments more than once.
At this point of time, I don't know how exactly SQL-standards define COALESCE.
As we see from previous point, actual implementations in RDBMS vary: some (e.g. MSSQL) make COALESCE to evaluate its arguments more than once, some (e.g. MySQL, PostgreSQL) — don't.
c-treeACE, which claims it's COALESCE implementation is SQL-92 compatible, says: "This function is not allowed in a GROUP BY clause. Arguments to this function cannot be query expressions." I don't know whether these restrictions are really within SQL-standard; most actual implementations of COALESCE (e.g. MySQL, PostgreSQL) don't have such restrictions. IFNULL/ISNULL, as normal functions, don't have such restrictions either.
Resume
Unless you face specific restrictions of COALESCE in specific RDBMS, I'd recommend to always use COALESCE as more standard and more generic.
The exceptions are:
Long-calculated expressions or expressions with side effects in MSSQL (as, per documentation, COALESCE(expr1, …) may evaluate expr1 twice).
Usage within GROUP BY or with query expressions in c-treeACE.
Etc.
Differences in SQL-Server:
There is no IFNULL() function but a similar ISNULL()
ISNULL takes only 2 parameters whereas COALESCE takes variable number of parameters
COALESCE is based on the ANSI SQL standard whereas ISNULL is a proprietary TSQL function
Validations for ISNULL and COALESCE is also different. For example, NULL value for ISNULL is converted to int, whereas for COAELSCE you have to provide a type. Ex:
ISNULL(NULL,NULL) : is int.
COALESCE(NULL,NULL) : will throw an error.
COALESCE(CAST(NULL as int),NULL) : is valid and returns int.
Data type determination of the resulting expression – ISNULL uses the first parameter type, COALESCE follows the CASE expression rules and returns type of value with highest precedence.
ifnull can only replace a null value of the first parameter. Whereas coalesce can replace any value with another value. With coalesce in standard SQL you can have many parameters transforming many values.
EDIT the example according to comments below.
Example: coalesce(null, null, null, 'b*', null, 'null*')
returns 'b*' and it is not possible to do with ifnull.
This db2 SQL will not work with COALESE, I will not see any rows retrieved.
Since I used IFNULL it is working as expected
select a.mbitno ,a.mbstqt,ifnull(b.apr,0)
from
(
select mmstcd,mbstat,mbfaci,mbwhlo,mbitno,mbstqt,MBALQT from libl.mitbal inner join libl.mitmas on
mmcono=mbcono and mmitno=mbitno
where mbcono=200 and mbstat in ('20','50') and mmstcd>0
)
as a left join
(
select mlfaci,mlwhlo,mlitno,mlstas,sum(mlstqt) as APR from libl.mitloc where mlcono=200 and mlstas='2'
group by mlfaci,mlwhlo,mlitno,mlstas
)
b on b.mlfaci=a.mbfaci and b.mlwhlo=a.mbwhlo and b.mlitno=a.mbitno
where a.mbitno in 'GWF0240XPEC' and a.mbstqt>0 and a.mbstqt<>ifnull(b.apr,0)
I have a query where I have to extract some number fields from varchar column.
When i do some replace and substring in select statement and cast it to bigint everything works fine, but when I use this same cast in join it throws error
'Error converting data type varchar to bigint'.
How is this possible?
select CAST(
case when CHARINDEX('/',f.BML,1)>0
then substring(replace(replace(replace(replace(replace(replace(replace(replace(replace(f.BML,'A',''),'B',''),'C',''),'+',''),',',''),'S',''),'H',''),'P',''),'¸','') ,1,CHARINDEX('/',BML,1)-1)
else replace(replace(replace(replace(replace(replace(replace(replace(replace(f.BML,'A',''),'B',''),'C',''),'+',''),',',''),'S',''),'H',''),'P',''),'¸','')
end as bigint)
from TableN n join TableO o on
n.Id=o.Id
join TableF f on
f.OId=o.OId and
substring(cast(n.RJ as varchar(10)),1,3)=substring(CAST(f.MT AS varchar(10)),1,3) and
CAST(
case when CHARINDEX('/',f.BML,1)>0 then substring(replace(replace(replace(replace(replace(replace(replace(replace(replace(f.BML,'A',''),'B',''),'C',''),'+',''),',',''),'S',''),'H',''),'P',''),'¸','') ,1,CHARINDEX('/',f.BML,1)-1)
else replace(replace(replace(replace(replace(replace(replace(replace(replace(f.BML,'A',''),'B',''),'C',''),'+',''),',',''),'S',''),'H',''),'P',''),'¸','')
end as bigint) =n.mbr
order by n.Ident
As I indicated in my comment, there's no guarantee on the order in which conditions are assessed. So if you have:
f.OId=o.OId and
substring(cast(n.RJ as varchar(10)),1,3)=substring(CAST(f.MT AS varchar(10)),1,3) and
CAST(
case when CHARINDEX('/',f.BML,1)>0 then substring(replace(replace(replace(replace(replace(replace(replace(replace(replace(f.BML,'A',''),'B',''),'C',''),'+',''),',',''),'S',''),'H',''),'P',''),'¸','') ,1,CHARINDEX('/',f.BML,1)-1)
else replace(replace(replace(replace(replace(replace(replace(replace(replace(f.BML,'A',''),'B',''),'C',''),'+',''),',',''),'S',''),'H',''),'P',''),'¸','')
end as bigint) =n.mbr
And either f.OId=o.OId or substring(cast(n.RJ as varchar(10)),1,3)=substring(CAST(f.MT AS varchar(10)),1,3) should eliminate rows with values of BML that are not convertible to bigint, that's no guarantee that the conversion will not be attempted.
You can attempt to move the filters that should eliminate bad BML values into a subquery or CTE, but that's still no guarantee that the query optimizer won't push the conversion operator down into the subquery and still cause an error.
The only real way to deal with this (unfortunately) is to split the query into two pieces, eliminating unconvertible values in the first query, and placing the result of this query in a temp table/table variable. Then build the second half of the query using this temp table.