Error with casting - sql-server-2008

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.

Related

How Coalesce function deals with datatype

I am new to COALESCE function in REDSHIFT. I ran below four queries in mysql and Redshift.
1st and 2nd query executed as expected in both mysql and redshift. But for 3rd and 4th query I am getting two different results in mysql and Redshift. How does this behave?
select COALESCE(null,null,1) -> 1
select COALESCE(null,null,'John') -> 1
select COALESCE(null,null,1,'John') -> (Redshift : error , mysql:1)
select COALESCE(null,null,'John',1) -> (Redshift: error, mysql:John)
Also this query should give error in mysql but it has succeeded
Any help is appreciated
Amazon Redshift Database Developer Guide claims:
An NVL expression is identical to a COALESCE expression. NVL and
COALESCE are synonyms.
Syntax
NVL | COALESCE ( expression, expression, ... )
An NVL or COALESCE expression returns the value of the first expression
in the list that is not null. If all expressions are null, the result
is null. When a non-null value is found, the remaining expressions in
the list are not evaluated.
This type of expression is useful when you want to return a backup
value for something when the preferred value is missing or null. For
example, a query might return one of three phone numbers (cell, home,
or work, in that order), whichever is found first in the table (not
null).
If you obtain the error this may mean that the returned value datatype do not match the datatype of recordset field or any another structure which must accept the returned value.
PS. Will you show error messages?
Though it is not written in the documentation, but coalesce works on the compatible data types. Integer and varchar cannot be compared.
The error becomes more evident when you provide column name instead of hard-code values. Try executing this:
select coalesce(integer_column, varchar_column) from a_table;
You would get an error saying something like this:
coalesce types integer and varchar cannot be matched.

Arithmetic overflow error converting varchar to data type numeric ONLY in WHERE

I have this query....
SELECT
CONVERT(NUMERIC(8, 2), ResultLevel),
*
FROM
dbo.DrugTestResult
WHERE
DrugID = 'THC'
AND ISNUMERIC(ResultLevel) = 1
AND (CONVERT(NUMERIC(8, 2), ResultLevel) >= 50
AND CONVERT(NUMERIC(8, 2), ResultLevel) <= 99999)
AND CONVERT(DATE, AuditStamp) > '2014-1-1'
Which returns this error
Arithmetic overflow error converting varchar to data type numeric
When I comment this part of the where clause
AND ( CONVERT(NUMERIC(8, 2), ResultLevel) >= 50
AND CONVERT(NUMERIC(8, 2), ResultLevel) <= 99999
)
The data set is returned.
So the question is why does the CONVERT work in the SELECT, but not in the WHERE clause?
Because the different elements of the WHERE clause can get evaluated in any order that the query processing engine deems fit, so it can try to evaluate the CONVERT() before it evaluates the ISNUMERIC(). Therefore it can try to convert data that can't be converted.
The SELECT list, on the other hand, is evaluated after the WHERE clause, so the ISNUMERIC() has eliminated values that can't be converted.
To avoid your error, you can put the ISNUMERIC() on an inner derived table, so that you only try to CONVERT() data that is numeric in your outer WHERE clause.
Because there are one or more records that can't be converted as requested. If you run your query in SSMS it will execute the conversion in the select clause only for those rows displayed from the resultset, meanwhile the where clause is executed for all rows in the resultset to determine which rows are included in the resulset. To test this you can execute the query (without the where clause) and scroll down: once you reach the row that is messing you you will get the conversion error.
Hope this answers your question and explains that behavior.

MySQL returns all rows when field=0 from SECOND Select query

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

How to use a mysql variable from one table as a subquery in another, but casting it as a string (from int)

This is the query i'm trying to run:
UPDATE files set refcount=
(
SELECT count(*)
FROM comments WHERE data=files.id
)
WHERE id=?;
The problem is, comments.data is a text column (for other reasons). So I need to cast files.id as a STRING instead of what it is (an INT), because otherwise the comments.data index won't be used.
For example, this query runs fine:
SELECT count(*) FROM comments WHERE data='1234';
But this one takes forever (because it cannot use the index, comments has 10M rows):
SELECT count(*) FROM comments WHERE data=1234;
Perhaps I need to use #vars or something? I tried putting the thing in quotes, but that uses the literal "files.id" i think.
UPDATE files set refcount=
(
SELECT count(*)
FROM comments WHERE data='files.id'
)
WHERE id=?;
All you have to do is to cast files.id into string before comparing it to data
something like this :
UPDATE files set refcount=
(
SELECT count(*)
FROM comments WHERE data=CAST(files.id AS vachar)
)
WHERE id=?;
Here's a link that show how you can use cast functions and operators in mysql.
UPDATED: It seems that for some reasons CAST is not working with varchar.Though char might do the trick (whih in case it doesn't as Timh said in the comments below) CONCAT can be used to convert other types to a varchar (when you concat othery types with a string it returns a string and concating with an empty string will act as some sort of conversion :) )

Linq-to-SQL expression to get the max numeric value from a text column

I have an nvarchar SQL column which contains mostly numeric values. I'm trying to come up with an L2S expression that gets me the maximum numeric value while ignoring any non-numeric values.
The SQL that does the job is:
select top 1 value from identifier where and patindex('%[^0-9]%', value) = 0 order by CAST(value AS INT) desc
What LINQ expression can I use to achieve the same thing?
You can do SQL Like queries using the SqlMethods in System.Data.Linq.SqlClient.
(from a in identifier
where !SqlMethods.Like(a.value, "%[^0-9]%")
select a).Max(x => Convert.ToInt64(x.value))
This Linq statement becomes this query according to LinqPad:
-- Region Parameters
DECLARE #p0 VarChar(8) = '%[^0-9]%'
-- EndRegion
SELECT MAX([t1].[value]) AS [value]
FROM (
SELECT CONVERT(BigInt,[t0].[value]) AS [value], [t0].[value]
FROM [Identifier] AS [t0]
) AS [t1]
WHERE NOT ([t1].[value] LIKE #p0)
LinqPad is a great way to play around with queries to see if you can get what you're looking for. I've found that just about the only SQL statements that don't have a good L2S equivalent are ones with the PIVOT keyword. Other than that, there's usually a way to get what you want.
If you want the whole record and not just the MAX() value, you could do the query this way:
(from a in Accounts
orderby (!SqlMethods.Like(a.AccountNumber, "%[^0-9]%") ?
Convert.ToInt64(a.AccountNumber) : 0)
descending
select a).Take(1)