CAST, SUM, CASE Issues - sql

I am trying to accommodate for some rogue values in my database, that contain the string 'unknown', I want to set these to 0 and then sum the rest. But for some reason, this isnt happening. Here is what I have -
Values - VARCHAR(30) -
3
0.1
2
16
2
5
2
Unknown
2.4
7
Unknown
And here is my Cast,Sum,Case
Cast(sum(case when stake = 'Unknown' then 0 else stake end) as float) as totalStake
But I get this error - Conversion failed when converting the varchar value '0.1' to data type int.
Help!
Thanks

You must cast stake as a float:
sum(case when stake = 'Unknown' then 0.0 else cast(stake as float) end) as totalStake

You should explicitly convert to some sort of numeric values. Try this:
sum(try_convert(numeric(18, 4), stake)) as totalStake
Your code has at least two issues. First, your case expression returns an integer (because the first then has an integer). So, it tries to convert stake to an integer, which can generate an error.
Second, you should be doing arithmetic operations on data that is explicitly some sort of number type and not rely on implicit conversion.

You can try the following query using isnumeric() to check numeric data.
create table temp (stake VARCHAR(30))
insert into temp values
('3'), ('0.1'), ('2'), ('16'), ('2'), ('5'), ('2'), ('Unknown'), ('2.4'), ('7'), ('Unknown')
--Select * from temp
Select sum(Cast(stake as Float)) from temp where isnumeric(stake) = 1
To handle some exception like null values or . values only you can try this
Select SUM(TRY_CAST(stake as Float)) from temp
You can find the live demo Here.

Initial step would be to replace the 'Unknown' string with 0 using a replace function and then convert the column datatype to the one which allows to perform Aggregate functions and then perform SUM on top of that. The below query will work only for 'unknown' string, if you have different strings other than 'unknown' you might have to choose a different approach like using IsNumeric in Replace function and update the string value to 0.
select sum(cast((REPLACE(stake,'unknown',0)) as float)) from table

This happens because SQL has some problems while converting decimal values to integer values.
In facts, function sum returns integer values
I solved it using round function on the values1 variable ( sorry for using same name for table and column ):
select Cast(sum(case when values1 = 'Unknown' then 0 else round(values1, 2) end) as
float)as totalstrike
from values1

Related

SQL SERVER 2019 - LEN(FLOOR(CAST([value] AS FLOAT))) defaulting to 12

I am running the following code to get the length of a value before the decimal place:
SELECT LEN(FLOOR(CAST([VALUE] AS FLOAT))) FROM TABLE1 WHERE VALUE2 <> 'B'
The [VALUE] column in TABLE1 is of type nvarchar(30) hence the cast. The column also contains some non-numeric values but these are filtered out by the WHERE clause as they all have a 'B' value for VALUE2.
The code works as expected and returns '6' for values with 6 digits such as '123456.123'. It also works correctly for values with less than 6 digits. However, the code simply returns '12' for any value with greater than 6 digits such as '12345678'.
I've done some googling and can't seem to find a reason for this? Any explanations / alterations / alternatives would be much appreciated!
LENGTH() function expects string expression, so the float value is implicitly converted to string using scientific notation. The following statement demonstrates this issue and the unexpected result:
SELECT
LEN(FLOOR(CAST([VALUE] AS FLOAT))),
FLOOR(CAST([VALUE] AS FLOAT)),
CONVERT(varchar(50), FLOOR(CAST([VALUE] AS FLOAT)))
FROM (VALUES
(N'12345678')
) TABLE1 ([VALUE])
Result:
12 12345678 1.23457e+007
A possible solution, without using an integer (and/or float) conversion, is the following statement:
SELECT CHARINDEX(N'.', CONCAT([VALUE], N'.')) - 1
FROM (VALUES
(NULL),
(N'12345678'),
(N'123456.123'),
(N'99999.923')
) TABLE1 ([VALUE])
I am running the following code to get the length of a value before the decimal place:
This value is called the log base 10 plus 1 -- at least for numbers greater than 1. So how about using:
floor(log10(value)) + 1
You can tweak this for values less than 1 (including negative values) if that is needed.

REPLACE to just have a number causing conversion failure

I'm trying to do a count to see how many fields in column value are > 10:
SELECT
COUNT(CASE WHEN t.value > 10)
THEN 1
ELSE NULL
END
FROM table t
WHERE t.DATE = '2017-01-01'
However, the column has a few custom entries like +15 or >14.0, so I added the following:
SELECT
COUNT(CASE WHEN value LIKE '>%'
and Replace(value, '>', '') > 10)
FROM table t
WHERE t.DATE = '2017-01-01'
However, after doing that, I get the following error:
Conversion failed when converting the varchar value '>14.0' to data
type int. Warning: Null value is eliminated by an aggregate or other
SET operation.
Seeing I have no access to rewrite the database with an UPDATE, does anyone have a workaround solution?
You could fix this, either by simply changing 10 to 10.0:
SELECT CASE WHEN '14.0' > 10.0 THEN 1 ELSE 0 END
This will cause the implicit conversion of '14.0' to decimal rather than int, which works, or you explicitly convert it:
SELECT CASE WHEN CONVERT(DECIMAL(14, 2), '14.0') > 10 THEN 1 ELSE 0 END
If it were me however, and I was not in a position to update the data, and do something a bit left field, like use a numeric data type to store numbers, I would ignore these values completely, and simply use TRY_CONVERT to avoid the conversion errors:
SELECT
COUNT(CASE WHEN TRY_CONVERT(DECIMAL(14, 2), value) > 10 THEN 1 END)
It is a varchar column, so the possibilities of what nonsense could be in there are endless, you might get a query that works now by replacing > and +, but then what about when someone puts in <, or ends up with a space in between like + 14, or something completely random like 'aaaa', where does it end?
It would be helpful to see the table and sample data, but it sounds like you have strings that are numbers and a sign.
You can cast it to convert the data since you are mixing and matching data types.
SELECT
COUNT(CASE WHEN CAST(value AS VARCHAR(10)) LIKE '>%'
and CAST(Replace(value, '>', '') AS your_num_datatype_here) > 10)

how to convert id datatype in sql server

I have data like
id
27.45
29.1
27.45
21.95
18.1
51.75
0
21.45
41.94
21.95
32.95
My query is
SUM(CASE WHEN ab.dates BETWEEN bc.fst_sales_date AND BC.[WEEK4] THEN
[salesval] -- my initial try
ELSE 0 END) week4_qtyvalues
facing error
Conversion failed when converting the nvarchar value '41.94' to data
type int.
I have checked
SUM(CASE WHEN ab.dates BETWEEN bc.fst_sales_date AND BC.[WEEK4] THEN
CONVERT(float,[salesval]) -- this is what I've tried
ELSE 0 end) week4_qtyvalues
and
SUM(CASE WHEN ab.dates between bc.fst_sales_date AND BC.[WEEK4] THEN
CAST([salesval]AS int) -- this is what I've tried
ELSE 0 END) week4_qtyvalues
Regardless of my tries , I'm still facing the same error.
DECLARE #t TABLE (id VARCHAR(10))
INSERT INTO #t (id)
VALUES
('27.45'),('29.1'),('27.45'),('21.95'),('18.1'),
('51.75'),('0'),('21.45'),('41.94'),('21.95'),('32.95')
SELECT SUM(CASE WHEN id IS NOT NULL THEN CAST(id AS FLOAT) ELSE 0 END)
FROM #t
That is happening because you have a nvarchar and not a float number to cast to int. You should first cast the [salesval] to float and after that cast it to int. Something like this:
CAST(CAST([salesval] AS float) AS INT)
Because of the way SQL Server handles statements with multiple data types mixed together, it'll still try to take your salesval field and treat it as an int.
So, firstly, try casting the 0 as well.
And secondly, you almost certainly don't want to use float - it's for scientific calculations that need its huge range only and isn't precise. Try decimal instead.

Convert exponential to number in sql

I have a large amount of card tokens (16 digits) uploaded from xml file to sql-server. The problem is I see them as expression, sample below:
3.3733E+15
3.3737E+15
3.3737E+15
3.3737E+15
3.37391E+15
3.37391E+15
3.37398E+15
3.37453E+15
3.37468E+15
3.37468E+15
3.3747E+15
3.37486E+15
3.37486E+15
3.37567E+15
3.3759E+15
3.3759E+15
Any suggestion to change them to a 16 digit number? I have tried to change the data type, but got error"Conversion failed when converting the varchar value '3.37201E+15' to data type int"
Thanks for help!
Edit:
#X.L.Ant see my code below. I create this table from another one, which is just purely inserted from xml file. Is this may cause an error because some rows are empty in column TOKEN?
CREATE TABLE MULTICURRENCY_CHECK
(
TOKEN varchar(255)
)
/*Merges all card tokens into 1 column, as in xml they are spread across different columns*/
INSERT INTO MULTICURRENCY_CHECK
(
TOKEN
)
SELECT no FROM gpstransactionsnew2
UNION ALL
SELECT no19 FROM gpstransactionsnew2
UNION ALL
SELECT no68 FROM gpstransactionsnew2
UNION ALL
SELECT no93 FROM gpstransactionsnew2
UNION ALL
SELECT no107 FROM gpstransactionsnew2
UNION ALL
SELECT no121 FROM gpstransactionsnew2
SELECT REPLACE(TOKEN, 'OW1', ' ')
FROM MULTICURRENCY_CHECK
/*Converts exponential expression to number*/
SELECT CONVERT(numeric(16,0), CAST(TOKEN AS FLOAT))
FROM MULTICURRENCY_CHECK
Try to cast your string to float before converting it :
SELECT CONVERT(numeric(16,0), CAST(TOKEN AS FLOAT))
FROM MULTICURRENCY_CHECK
See this fiddle.
I don't know what's the format of those numbers in your XML source, but with the data you provide, you'll end up with 33733 for instance followed by a bunch of zeroes. If you have a bigger precision in your XML, maybe you should tweak your importing settings to keep this precision instead of trying to deal with that in the DB.
EDIT:
Try testing your strings with ISNUMERIC to avoid the casting errors you're getting. Adding a raw output of your column will allow you to check which value fails to convert (i.e. converts to 0).
SELECT TOKEN,
CONVERT(NUMERIC(16, 0), CAST(CASE
WHEN ISNUMERIC(TOKEN) = 1
THEN TOKEN
ELSE 0
END AS FLOAT))
FROM MULTICURRENCY_CHECK
For SQL Server 2012+, use TRY_CONVERT().
The use of ISNUMERIC() in xlecoustillier's edited answer does not protect against conversion failures.
Given the following scenario:
CREATE TABLE test(a varchar(100));
insert into test values ('3.3733E+15'),
('3.3737E+15'),
('3.37391E+30'), --fails conversion. included to demonstrate the nature of TRY_CONVERT().
('3.37398E+15'),
('3.37453E+15'),
('3.37468E+15'),
('3.3747E+15'),
('3.37486E+15'),
('3.37567E+15'),
('3.3759E+15');
SELECT TRY_CONVERT(numeric(16,0), CAST(a AS FLOAT))
FROM test
Results in only valid converted values:
---------------------------------------
3373300000000000
NULL
3373910000000000
3373980000000000
3374530000000000
3374680000000000
3374700000000000
3374860000000000
3375670000000000
3375900000000000
However:
SELECT a,
CONVERT(NUMERIC(16, 0), CAST(CASE
WHEN ISNUMERIC(a) = 1
THEN a
ELSE 0
END AS FLOAT))
FROM test
Fails with:
Conversion failed when converting the varchar value '3.3733E+15' to
data type int.
The issue is that all values in the 'a' column return 1 when passed to the ISNUMERIC() function.
SELECT CASE WHEN ISNUMERIC(a) = 1 THEN 'Yes' ELSE 'No' END as IsValueNumeric
FROM test
Try it on SQLFiddle and/or compare with xlecoustillier's sqlfiddle
SELECT colmn_name || '' FROM table_name
This should work.

SQL Server : ignore strings in SUM function

I do a sum function over a column. But the column can have string values also. I want SQL Server to ignore the string values and sum only the string values.
Eg: column can have values like 16000Euro or 2588, or 3671.
The input is from user and I cant change validation in the app to integer
I have tried this but still shows error:
SUM(CASE WHEN Type_New = 202 AND ISNUMERIC(Summe) = 1
THEN Summe
ELSE 0
END) AS total_Euro
So how can I ignore the string values when doing sum operation?
The error I get is:
Error converting nvarchar value '2588. 'in the int data type.
EDIT: I want SQL to ignore such string values and sum what it can.. The main aim is that Query should not throw any error
Try the below Query, it will work perfectly :)
SELECT SUM(CASE WHEN Type_New = 202 AND ISNUMERIC(Summe + '.0e0') = 1
THEN Summe
ELSE 0
END) AS total_Euro FROM TableName
IsNumeric returns 1 if the varchar value can be converted to ANY number type (includes int, bigint, decimal, numeric, real & float) Values like 1e4,1., 2.0 will create the issue if the above check to bypass these values is not added.
You should not name column same as a keyword in SQL Server , if this cannot be avoided you can escape column name by enclosing in square bracketes [Sum] as shown below
SELECT SUM(CASE WHEN Type = 202 AND ISNUMERIC([Sum]) = 1 THEN [Sum] ELSE 0 END) AS total_Euro
Try this
SUM(CASE WHEN Type = 202 AND case when Sum not like '%[^0-9]%' THEN Sum END ELSE 0 END) AS total_Euro
or
SUM(CASE WHEN Type = 202 AND ISNUMERIC(Sum+'.e0') = 1 THEN Sum ELSE 0 END) AS total_Euro
Try this:
SUM (CASE
WHEN Type_New = 202 AND ISNUMERIC(Summe) = 1 THEN CAST(summe AS DECIMAL(9,2))
ELSE 0 END) AS TotalEuro
I don't know if you do this SUM for one column or what, but also you can filter out what you need and then sum:
SELECT SUM(Summe) AS total_Euro
FROM someTable
WHERE Type_New = 202 AND ISNUMERIC(Summe) = 1
ISNUMERIC function considers strings that contain large numeric (e.g., 9223372036854775808), decimals (e.g., 12.4), currency figures (e.g., $123), and floating-point values (e.g., 1E2) to be strings that can be converted to a numeric data type.
Now to calculate Sum you will have to convert string to an integer[ this assumption is based on
sample data you have posted] but fact is string can be numeric but might not be convertible to an integer; the ISNUMERIC function is limited in the sense that it can tell you only whether the string can be converted to any numeric data type.
So if your column doesn't have string data like 1E3 or 12.4 or $123 which are numeric but not integers you can simply cast the target column to int as below and calculate the sum :
select SUM(CASE WHEN Type_New = 202 AND ISNUMERIC(Summe) = 1
THEN CAST(Summe AS INT)
ELSE 0
END) AS total_Euro
FROM test
else you shoudl go for a more generic function which as discussed here..
http://sqlmag.com/t-sql/can-i-convert-string-integer