How to test a condition in a sql case statement on numbers - sql

I would like to substitute all the values that are greater or equal to 10 with an empty string with a SQL CASE statement on my Microsoft SQL Server 2017. However, I am getting an error that reads:
Msg 102, Level 15, State 1, Line 13
Incorrect syntax near '>'.
Though there are some questions similar to my question, I can not find an answer that is specifically answering my question. For example this question here how to use > = condition in sql case statement?. I have also tried a dynamic query with a temporal table and this did not help.
Here is my code with the table definition and the test data as well as the actual query that I am running.
--table definition with two columns
declare #table table
(
person nvarchar(20),
digit decimal(10,2)
)
--insert test data with two records
insert into #table
select 'titimo', 9.51
union
select 'neriwo', 12.25
--the requirement is to not show the digit value if it is greater or equal to 10, but rather display an empty field.
--so, this is my select statement to meet this requirement that is failing
--with error message 'Incorrect syntax near >'
select
person,
case digit
when digit >= 10 then ''
else digit
end 'digit'
from #table
From my select statement above, I am expecting this output:
person digit
------ -----
titimo 9.51
neriwo
However, the output is not being generated because of the error message that I am experiencing.

You had a syntax error in your case. More over you cannot mix datatypes so you need to cast digit to varchar or change '' i.e. to null.
select
person,
case
when digit >= 10 then ''
else cast(digit as varchar(20))
end 'digit'
from #table

Your case is not formatted correctly - here's one option -
(also, you can't select text and numbers in the same column - so I casted your number to text... tweak to fit your needs)
select
person,
case when digit >=10 then ''
else CONVERT(VARCHAR(10), digit)
end 'digit'
from #table

Related

How to convert from nchar to decimal in SQL?

I have 2 tables(source and destination) which are respectively NOR_LABOR and ALL_LABOR_DETAILS. In the source table(NOR_LABOR) there is a column "feet_produced" with the data type "nchar(10)". In the destination table(ALL_LABOR_DETAILS) there's a column "labor_feet_produced" with the data type "decimal(18,4)". I want to convert the "feet_produced" from nchar(10) to decimal(18,4) and paste it in the "ALL_LABOR_DETAILS" table's "labor_feet_produced" column.
I have found a code regarding a simillar issue but did not do the exact as I need to do, following is that code snippet :
Select feet_produced AS feet_produced_s, CASE WHEN Isnumeric(feet_produced) = 1
THEN CONVERT(DECIMAL(18,2),feet_produced)
ELSE 0 END AS feet_produced
INTO [MES_DEV].[dbo].[ALL_LABOR_DETAILS]
from [dbo].[NOR_LABOR]
Thank you!
There are values that will test true for IS_NUMERIC, but will fail to convert to decimal.
Instead, use TRY_CONVERT which will return either the successfully-converted-to-decimal value, or a NULL when it fails. (You can then COALESCE to zero to get your desired result).
Here is a short example set of values, using TRY_CONVERT:
SELECT
TryConvert = COALESCE(TRY_CONVERT(decimal(18,4),TestValues),0)
FROM (
VALUES('10.6'),
('ten'),
('7d2'),
('10000000000'),
('10.00000001')
) AS x(TestValues);
The same set of values using your example code will throw an error:
SELECT
IsNumericCase = CASE
WHEN Isnumeric(TestValues) = 1
THEN CONVERT(DECIMAL(18,2),TestValues)
ELSE 0
END
FROM (
VALUES('10.6'),
('ten'),
('7d2'),
('10000000000'),
('10.00000001')
) AS x(TestValues);
This error is returned because 7d2 is numeric, but cannot be converted to decimal.
Msg 8114, Level 16, State 5, Line 14
Error converting data type varchar to numeric.
Im not sure what the issue is with the code that dose not work for you.
But here is how I would do it with a small change in the statement that you just post it.
insert into[MES_DEV].[dbo].[ALL_LABOR_DETAILS](labor_feet_produced)
select CONVERT(DECIMAL(18, 4), feet_produced) AS feet_produced_s from[dbo].[NOR_LABOR]

TSQL CASE unexpectedly processing multiple THEN statements

I have a simple SQL CASE statement that I am trying to interpret the datatype of a variable and then converting it to said format. I have the following sample:
DECLARE #P1 varchar(10) = '2';
SELECT CASE 1
WHEN ISNUMERIC(#P1) THEN (CAST(#P1 AS INT))
WHEN ISDATE(#P1) THEN (CAST(#P1 AS DateTime))
ELSE 'N' END AS Test2P1
I would expect it to return an integer value of 2. However, this is what I get.
Test2P1
1900-01-03 00:00:00.000
However, if I modify the code to just display a character instead of CASTING the variable, I get a different result:
DECLARE #P1 varchar(10) = '2';
SELECT CASE 1
WHEN ISNUMERIC(#P1) THEN 'I'
WHEN ISDATE(#P1) THEN 'D'
ELSE 'N' END AS Test2P1
Then I get a result of: I
Taking this experiment one step further, if I leave the first test returning an 'I' but casting the date, then I get an error:
DECLARE #P1 varchar(10) = '2';
SELECT CASE 1
WHEN ISNUMERIC(#P1) THEN 'I'
WHEN ISDATE(#P1) THEN (CAST(#P1 AS DateTime))
ELSE 'N' END AS Test2P1
Msg 241, Level 16, State 1, Line 3
Conversion failed when converting date and/or time from character string.
It appears that SQL is evaluating multiple instances of THEN statements. However, the ISDATE expression does NOT return true. I am stumped.
In my research, I came across this article [SQL Performance] (https://sqlperformance.com/2014/06/t-sql-queries/dirty-secrets-of-the-case-expression) What he is saying in this article makes complete sense. But I do not see where it applies in this situation as I am never changing the value of the variable.
I have also wrapped my CASE statement in COALESCE(), but it does not appear to help. I wouldn't have expected it to, but I found multiple articles referencing this as a solution to similar problems. This seems like a very simple CASE statement, but I do not know where I am going wrong. Any help is greatly appreciated.
DateTime has a higher datatype precedence in SQL Server than INT does, so your whole CASE is getting cast as DATETIME. You can only return data of a single datatype in one column, thus the need for datatype precedence.
Here is the MSDN article showing precedence.
Although I can't think of a good reason to do this, you could force the case expression to return sql_variant, which can store multiple different types, eg:
DECLARE #P1 varchar(10) = '2';
SELECT CASE 1
when 0 then cast(null as sql_variant)
WHEN ISNUMERIC(#P1) THEN (CAST(#P1 AS INT))
WHEN ISDATE(#P1) THEN (CAST(#P1 AS DateTime))
ELSE 'N' END AS Test2P1

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.

Get MAX value if column has a certain format

SQL Server 2008 R2
I have a table similar to this:
Example table:
ID Column
---------------
xxx1234
xxx12345
xxx123456
20150001
I am trying to get a conditional MAX value depending on the value of the column based on whether it meets as certain format. Using the above example, the fourth record, 20150001, represents a "good record" because it contains the current year, and the start of an increment. So, in my table, records that are considered "good" (those subject to the query I am trying to write) have the format "year + increment". The first three, that do not follow this format, should not be conditioned to the query since they don't match this format and should not be subject when computing the max value. Those are bad records. In the above example, the expected result would be "20150002".
The MAX query is simple enough to write, however I am wondering about an approach where I can sanitize the query to only include those records whom meet the particular format, and increment the last four digits (0001 to 0002).
TIA!
You can use the isdate function to filter out ID Columns that do not start with a valid year, and isnumeric to make sure the last 4 characters of the ID Column are valid increments. You also want the len to be 8, given this criteria. You can accomplish all this in the where clause:
-- load test data
declare #Example_Table table(ID_Column varchar(10))
insert into #Example_Table values
('xxx1234'),
('xxx12345'),
('xxx123456'),
('20150001')
-- return max valid ID_Column
select max(ID_Column) as max_ID_Column
from #Example_Table
where isdate(left(ID_Column,4)) = 1
and isnumeric(right(ID_Column,4)) = 1
and len(ID_Column) = 8
-- increment max valid ID_Column
update #Example_Table
set ID_Column = cast(ID_Column as int) + 1
where isdate(left(ID_Column,4)) = 1
and isnumeric(right(ID_Column,4)) = 1
and len(ID_Column) = 8
select * from #Example_Table
ID_Column
----------
xxx1234
xxx12345
xxx123456
20150002
You could use a regular expression to verify a correct year. The second half of the regular expression I taylored to your examples of 0001 and 0002, this could be opened up by adding '[0-9]' for each digit you're expecting.
DECLARE #Sample VARCHAR(30) = '20150001';
SELECT CASE WHEN (#Sample LIKE '[12][09][0-9][0-9]000[12]') THEN 'Yes' ELSE 'No' END;
SELECT
SUBSTRING(#Sample, 1, 4),
SUBSTRING(#Sample, 5, 4),
CASE WHEN (SUBSTRING(#Sample, 1, 4) LIKE '[12][09][0-9]') THEN 'Yes' ELSE 'No' END,
CASE WHEN (SUBSTRING(#Sample, 5, 4) LIKE '[0-9][0-9][0-9][0-9]') THEN 'Yes' ELSE 'No' END;

select case statement error in mssql

SELECT top 1
case
when VR = -99999.99
then 0
else cast((VR*1.732) as decimal(38,3))
end
FROM pseb.dbo.datasource
where FeederID=5003
order by datetime desc
The above query is working fine, but I need to return varchar value '--' instead of returning 0
if I do like that
SELECT top 1
case
when VR = -99999.99
then '--'
else cast((VR*1.732) as decimal(38,3))
end
FROM pseb.dbo.datasource
where FeederID=5003
order by datetime desc
means it returns the following error:
Msg 8114, Level 16, State 5, Line 1 Error converting data type varchar
to numeric.
please help me to solve it
The problem is that you are returning two different data types from the same column. The rule with SQL Server that numeric types take precedence over string types, i.e. in a situation like yours a string gets converted to a number, not the other way around.
So to solve this you can cast your number to a string.
One option is to do something like this:
SELECT top 1
case when VR = -99999.99 then '--'
else
cast
(
cast((VR*1.732) as decimal(38,3)
)
as varchar(50))
end
FROM pseb.dbo.datasource where FeederID=5003 order by datetime desc