Error when aggregating due to conversion from varchar to bigint - sql

Situation:
I want to aggregate a value from a table but i get the following error :
Error converting data type varchar to big int.
I've been reading countless of different solutions online but they don't seem to solve it.
Current query;
So based on the error message, i simply added the CAST function but it still doesnt work.
SELECT
base.target_date AS target_date
, base.game_id AS game_id
, base.device AS device
, ISNULL(CAST(SUM(use_point.point) AS bigint),0) AS result
FROM
cte AS base
LEFT JOIN cte2 AS use_point
ON base.target_date = use_point.target_date
AND base.game_id = use_point.device
AND base.device = use_point.device
GROUP BY
base.target_date
, base.device
, base.game_id
WITH ROLLUP
GO

I'm presuming that use_point.point is a VARCHAR, in which case simply change where you put your CAST statement:
, ISNULL(SUM(CAST(use_point.point AS bigint)), 0) AS result
Note that the CAST now takes place before the SUM.

Use TRY_CAST() instead. And it needs to be an argument to the SUM():
SELECT base.target_date, base.game_id, base.device,
COALESCE(SUM(TRY_CAST(use_point.point as bigint)), 0) as result
FROM . . .
Note that your column aliases are redundant, because you are assigning the default aliases.
You should also fix the data. Don't store numeric values as strings. To find the bad data, you can use:
select points
from use_points
where try_convert(points as bigint) is null and
points is not null;

Related

Conversion failed when converting the varchar value '6276.54' to data type int

I have the below query that keeps throwing the conversion error. I have tried so many ways of making this work but still get the same error. Process of elimination I'm now thinking that this is to do with the hard coded 0.715 value. I'm not sure if or how I force this to be a decimal or if its better to have this SET and a variable at the beginning of my code.
SELECT CAST(DATEPART(yyyy, YEAR) as INT) AS YEAR,
COUNT(ID) AS ID,
SUM(VALUE) AS VALUE,
SUM(PREMIUM) AS PREMIUM,
SUM(try_convert(float,USERID1)) AS VALUE1,
COALESCE(SUM(PREMIUM)/(SUM(try_convert(float,NULLIF(USERID1,0)))*0.715),0) AS 'PROFIT'
SUM(CAST(USERID1 AS float))/SUM(PREMIUM) AS 'PROFIT%'
INTO #YEAR_VALUE
FROM #DATA LT
INNER JOIN dbo.AccountDB P ON LT.ID = P.ID
GROUP BY INCEPTDATE
Any help would be much appreciate.
Thanks in advance
You have some logic back to front, you need to try_parse first, and then do nullif. Try_parse generally returns null if it cannot cast to type specified. You then need to convert null to 0.0
coalesce(sum(premium)/(sum(nullif(try_convert(float,'userId), 0.0)) * 0.715), 0.0) AS 'profit'
Also, use 0.0 for zero if expecting floats or decimals
Hint: save yours and the next person eyes, no need to use uppercase. That was back in the 70's
As it has been mentioned, It could be possible that you have some non-numerical data within that column. I did the best I could with what I can gather from here to throw together a quick mock up and it seems to work for me with data I have entered. Just testing the line of code you seem to be having issues with.
USE DB
GO
CREATE TABLE
Test_Table (
Premium decimal,
userID varchar(20)
)
INSERT INTO
Test_Table VALUES
(
2.5, 1
)
USE DB
GO
SELECT COALESCE(SUM(Premium)/(SUM(try_convert(float,NULLIF(userID,0)))*0.715),0) AS 'PROFIT'
FROM Test_Table;
That may point to either some non-numerical data or another line of code being the issue. Just food for though, I know our data and data types probably aren't the exact same.

Conversion failed when converting the varchar value 'x' to data type int

I have a WHERE condition which works for the type STRING but fails for an of type INT
isnull(emp.name, 'x') <> isnull(mst.name, 'x') -- works
But this condition below throws an error:
isnull(emp.age, 'x') <> isnull(mst.age, 'x') -- fails
Conversion failed when converting the varchar value 'x' to data type int.
where name is a STRING and age is of INT type.
How to rectify this?
Don't use isnull() for this purpose -- or even coalesce(). Just expand out the logic:
where (emp.age = mst.age or emp.age is null and mst.age is null)
You could put in a fake value and use coalesce(), but the types need to be consistent. However, I think you are better off with explicit logic that does what you want and works for all data types.
ISNULL will attempt to convert the datatype of second parameter to that of first parameter. The string x cannot be converted to int (assuming age is int). Use an integer value that, ideally, does not exist in your data:
isnull(emp.age, -1) <> isnull(mst.age, -1)
Note that in your code, 'x' will effectively be considered the same as NULL, which is unlikely to be what you want. Fixing the error you get for age will not correct that problem.
Consider instead using the operator IS DISTINCT FROM, which is similar to <> but considers NULL as a "known value" (NULL IS DISTINCT FROM NULL = FALSE for example).
emp.name IS DISTINCT FROM mst.name
emp.age IS DISTINCT FROM mst.age
If your database engine does not support IS DISTINCT FROM then this related question will be helpful: How to rewrite IS DISTINCT FROM and IS NOT DISTINCT FROM?

Converting data types in SQL Server

I need to change some data types. I have tried using the CAST keyword, but it is not fixing the issue. Any suggestions on how to re-write these two lines with CAST statements?
Data loss might occur when casting from VarChar(100) to VarChar(20).
Code:
SELECT TOP 1 #variableId = variableId
FROM #tempTable
Data loss might occur when casting from NVarChar(512) to NVarChar.
Code:
SELECT myVariable
FROM tableName
I tried doing something like the following, but still produces an error:
CAST((myVariable) as nvarchar)
CAST is used for converting between data types. It sounds more like you should use LEFT instead:
SELECT TOP 1 #variableId = LEFT(variableId,20)
FROM #tempTable
This won't give you any warning as the system assumes you already know you're going to lose the right 80 characters.
For using CONVERT instead of CAST:
CONVERT(nvarchar, myVariable)
Is a valid syntax and also:
CONVERT(varchar(20), myVariable)
But for getting a part of a string we use SUBSTRING() or LEFT() or RIGHT() functions like this:
SUBSTRING( value_expression , start_expression , length_expression )
Returns part of a character, binary, text, or image expression.
LEFT ( character_expression , integer_expression )
Returns the left part of a character string with the specified number of characters.
RIGHT ( character_expression , integer_expression )
Returns the right part of a character string with the specified number of characters.

Why would YEAR fail with a conversion error from a Date?

I got a view named 'FechasFirmaHorometros' defined as
SELECT IdFormulario,
CONVERT(Date, RValues) AS FechaFirma
FROM dbo.Respuestas
WHERE ( IdPreguntas IN (SELECT IdPregunta
FROM dbo.Preguntas
WHERE
( FormIdentifier = dbo.IdFormularioHorometros() )
AND ( Label = 'SLFYHDLR' )) )
And i have a Function named [RespuestaPreguntaHorometrosFecha] defined as
SELECT Respuestas.RValues
FROM Respuestas
JOIN Preguntas
ON Preguntas.Label = #LabelPregunta
JOIN FechasFirmaHorometros
ON FechasFirmaHorometros.IdFormulario = Respuestas.IdFormulario
WHERE Respuestas.IdPreguntas = Preguntas.IdPregunta
AND YEAR(FechasFirmaHorometros.FechaFirma) = #Anio
AND MONTH(FechasFirmaHorometros.FechaFirma) = #Mes
#LabelPregunta VARCHAR(MAX)
#Anio INT
#Mes INT
I keep getting this message upon hitting the aforementioned function while debugging another stored procedure that uses it
Conversion failed when converting date and/or time from character string.
Yet i can freely do things like
SELECT DAY(FechaFirma) FROM FechasFirmaHorometros
Why is this happening and how can i solve or work around it?
I assume that RValues is a string column of some type, for some reason. You should fix that and store date data using a date data type (obviously in a separate column than this mixed bag).
If you can't fix that, then you can prevent what Damien described above by:
CASE WHEN ISDATE(RValues) = 1 THEN CONVERT(Date, RValues) END AS FechaFirma
(Which will make the "date" NULL if SQL Server can't figure out how to convert it to a date.)
You can't prevent this simply by adding a WHERE clause, because SQL Server will often try to attempt the conversion in the SELECT list before performing the filter (all depends on the plan). You also can't force the order of operations by using a subquery, CTE, join order hints, etc. There is an open Connect item about this issue - they are "aware of it" and "hope to address it in a future version."
Short of a CASE expression, which forces SQL Server to evaluate the ISDATE() result before attempting to convert (as long as no aggregates are present in any of the branches), you could:
dump the filtered results into a #temp table, and then subsequently select from that #temp table, and only apply the convert then.
just return the string, and treat it as a date on the client, and pull YEAR/MONTH etc. parts out of it there
just use string manipulation to pull YEAR = LEFT(col,4) etc.
use TRY_CONVERT() since I just noticed you're on SQL Server 2012:
TRY_CONVERT(DATE, RValues) AS FechaFirma

How does one filter based on whether a field can be converted to a numeric?

I've got a report that has been in use quite a while - in fact, the company's invoice system rests in a large part upon this report (Disclaimer: I didn't write it). The filtering is based upon whether a field of type VarChar(50) falls between two numeric values passed in by the user.
The problem is that the field the data is being filtered on now not only has simple non-numeric values such as '/A', 'TEST' and a slew of other non-numeric data, but also has numeric values that seem to be defying any type of numeric conversion I can think of.
The following (simplified) test query demonstrates the failure:
Declare #StartSummary Int,
#EndSummary Int
Select #StartSummary = 166285,
#EndSummary = 166289
Select SummaryInvoice
From Invoice
Where IsNull(SummaryInvoice, '') <> ''
And IsNumeric(SummaryInvoice) = 1
And Convert(int, SummaryInvoice) Between #StartSummary And #EndSummary
I've also attempted conversions using bigint, real and float and all give me similar errors:
Msg 8115, Level 16, State 2, Line 7
Arithmetic overflow error converting
expression to data type int.
I've tried other larger numeric datatypes such as BigInt with the same error. I've also tried using sub-queries to sidestep the conversion issue by only extracting fields that have numeric data and then converting those in the wrapper query, but then I get other errors which are all variations on a theme indicating that the value stored in the SummaryInvoice field can't be converted to the relevant data type.
Short of extracting only those records with numeric SummaryInvoice fields to a temporary table and then querying against the temporary table, is there any one-step solution that would solve this problem?
Edit: Here's the field data that I suspect is causing the problem:
SummaryInvoice
11111111111111111111111111
IsNumeric states that this field is numeric - which it is. But attempting to convert it to BigInt causes an arithmetic overflow. Any ideas? It doesn't appear to be an isolated incident, there seems to have been a number of records populated with data that causes this issue.
It seems that you are gonna have problems with the ISNUMERIC function, since it returns 1 if can be cast to any number type (including ., ,, e0, etc). If you have numbers longer than 2^63-1, you can use DECIMAL or NUMERIC. I'm not sure if you can use PATINDEX to perform an regex look on SummaryInvoice, but if you can, then you should try this:
SELECT SummaryInvoice
FROM Invoice
WHERE ISNULL(SummaryInvoice, '') <> ''
AND CASE WHEN PATINDEX('%[^0-9]%',SummaryInvoice) > 0 THEN CONVERT(DECIMAL(30,0), SummaryInvoice) ELSE -1 END
BETWEEN #StartSummary And #EndSummary
You can't guarantee what order the WHERE clause filters will be applied.
One ugly option to decouple inner and outer.
SELECT
*
FROM
(
Select TOP 2000000000
SummaryInvoice
From Invoice
Where IsNull(SummaryInvoice, '') <> ''
And IsNumeric(SummaryInvoice) = 1
ORDER BY SummaryInvoice
) foo
WHERE
Convert(int, SummaryInvoice) Between #StartSummary And #EndSummary
Another using CASE
Select SummaryInvoice
From Invoice
Where IsNull(SummaryInvoice, '') <> ''
And
CASE WHEN IsNumeric(SummaryInvoice) = 1 THEN Convert(int, SummaryInvoice) ELSE -1 END
Between #StartSummary And #EndSummary
YMMV
Edit: after question update
use decimal(38,0) not int
Change ISNUMERIC(SummaryInvoice) to ISNUMERIC(SummaryInvoice + '0e0')
AND with IsNumeric(SummaryInvoice) = 1, will not short circuit in SQL Server.
But may be you can use
AND (CASE IsNumeric(SummaryInvoice) = 1 THEN Convert(int, SummaryInvoice) ELSE 0 END)
Between #StartSummary And #EndSummary
Your first issue is to fix your database structure so bad data cannot get into the field. You are putting a band-aid on a wound that needs stitches and wondering why it doesn't heal.
Database refactoring is not fun, but it needs to be done when there is a data integrity problem. I assume you aren't really invoicing someone for 11,111,111,111,111,111,111,111,111 or 'test'. So don't allow those values to ever get entered (if you can't change the structure to the correct data type, consider a trigger to prevent bad data from going in) and delete the ones you do have that are bad.