SQL case statement error handling when there are non-integer values - sql

I have a field of 5 digit codes, and I am trying to create a new flag field if the 5 digit code is between 2 numbers. That part is easy, but there are also a lot of values that have letters and aren't strictly 5 digits. So I'm trying to put a statement at the beginning of the case statement that says if there's an error then set the flag to zero. Or a statement that says if the value is not a number then set to zero.
Here's a sample of listed values:
36569
38206
J8502
JAA8C
Here is some code I've tried (simplified to get the point across):
case
when not isnumeric([code]) then 'N'
when [code] between 50000 and 50005 then 'Y'
ELSE 'N'
end as NewFlag
Thanks!

How about using try_cast() or try_convert():
(case when try_convert(int, code) between 50000 and 50005
then 'Y' else 'N'
end) as newFlag
Actually for your particular values, you can do the comparison as strings:
(case when code between '50000' and '50005'
then 'Y' else 'N'
end) as newFlag
This is really a special case, because you have 5 digit codes and you are only concerned about the last character.

Related

type cast in Case statement

Segment
1
2
3
4
NUll
5
I want to impute 'Other' if the Segment value is null
expected output
Segment
1
2
3
4
Other
5
i have tried
select
case when segment is null then 'Other' else segment end as segment
from table;
It says invalid input syntax for type "numeric":Other
The case expression returns a single type. The problem is that segment is a number, but 'Other' is a string. The expression has to make a choice, and it chooses the numeric type (following standard SQL rules).
This is simple to fix. Just cast segment:
select (case when segment is null then 'Other' else segment::text end) as segment
from table;
It would be more natural to write this query using coalesce():
select coalesce(segment::text, 'Other') as segment
from table;
select
case when CAST(segment AS CHAR) IS NULL then 'Other' else CAST(segment AS CHAR) end as segment
from table

Error in SQL case statement when trying to create binary flag?

Here's my query where I'm testing my case structure:
SELECT TOP 1 CASE 130
WHEN '000000000000000' THEN '0'
WHEN '' THEN '0'
WHEN 'XXX' THEN '0'
WHEN 'RETIRED' THEN '0'
WHEN 'STUDENT' THEN '0'
ELSE '1'
END AS employed_flag
INTO #employedbeta
FROM CreditBureau.Experian
I'm just trying to make a new temporary table, but I'd like my case to work first. I keep getting the error:
Conversion failed when converting the varchar value 'XXX' to data type int.
In the database, the column 130 is a char, and I don't know why it thinks I want to make it a number. SQL server management studio, if it matters.
The column name is 130, I left the '1' off because I rewrote it here but I get the error regardless in my actual query.
130 is an integer literal. If that's really the column name, you'll have to escape it using double quotes. As a side note, you should probably return the same type (char) in the else branch too:
CASE "130"
WHEN '000000000000000' THEN '0'
WHEN '' THEN '0'
WHEN 'XXX' THEN '0'
WHEN 'RETIRED' THEN '0'
WHEN 'STUDENT' THEN '0'
ELSE '1'
END AS employed_flag
130 is a really bad column name. But, I would simplify the logic to:
SELECT TOP 1 (CASE WHEN [130] IN ('000000000000000', '', 'XXX', 'RETIRED', 'STUDENT')
THEN 0 ELSE 1
END) AS employed_flag
INTO #employedbeta
FROM CreditBureau.Experian;
Note that I also changed the employed_flag to a numeric value rather than a string. That makes more sense to me.

Invalid argument for function integer IBM DB2

I need to filter out rows in table where numer_lini column has number in it and it is between 100 and 999, below code works just fine when i comment out line where i cast marsnr to integer. However when i try to use it i get error: Invalid character found in a character string argument of the function "INTEGER". when looking at the list seems like replace and translate filters only numbers just fine and select only contains legit numbers (list of unique values is not long so its easy to scan by eye). So why does it fail to cast something? I also tried using integer(marsnr), but it produces the same error. I need casting because i need numeric range, otherwise i get results like 7,80 and so on. As I mentioned Im using IBM DB2 database.
select numer_lini, war_trasy, id_prz1, id_prz2
from alaska.trasa
where numer_lini in (
select marsnr
from (
select
distinct numer_lini marsnr
from alaska.trasa
where case
when replace(translate(numer_lini, '0','123456789','0'),'0','') = ''
then numer_lini
else 'no'
end <> 'no'
)
where cast(marsnr as integer) between 100 and 999
)
fetch first 300 rows only
If you look at the optimized SQL from the Db2 explain, you will see that Db2 has collapsed your code into a single select.
SELECT DISTINCT Q2.NUMER_LINI AS "NUMER_LINI",
Q2.WAR_TRASY AS "WAR_TRASY",
Q2.ID_PRZ1 AS "ID_PRZ1",
Q2.ID_PRZ2 AS "ID_PRZ2",
Q1.NUMER_LINI
FROM ALASKA.TRASA AS Q1,
ALASKA.TRASA AS Q2
WHERE (Q2.NUMER_LINI = Q1.NUMER_LINI)
AND (100 <= INTEGER(Q1.NUMER_LINI))
AND (INTEGER(Q1.NUMER_LINI) <= 999)
AND (CASE WHEN (REPLACE(TRANSLATE(Q1.NUMER_LINI,
'0',
'123456789',
'0'),
'0',
'') = '') THEN Q1.NUMER_LINI
ELSE 'no' END <> 'no')
Use a CASE to force Db2 to do the "is integer" check first. Also, you don't check for the empty string.
E.g. with this table and data
‪create‬‎ ‪TABLE‬‎ ‪alaska‬‎.‪trasa‬‎ ‪‬‎(‪numer_lini‬‎ ‪VARCHAR‬‎(‪10‬‎)‪‬‎,‪‬‎ ‪war_trasy‬‎ ‪INT‬‎ ‪‬‎,‪‬‎ ‪id_prz1‬‎ ‪INT‬‎,‪‬‎ ‪id_prz2‬‎ ‪INT‬‎)‪;
insert into alaska.trasa values ('',1,1,1),('99',1,1,1),('500',1,1,1),('3000',1,1,1),('00300',1,1,1),('AXS',1,1,1);
This SQL works
select numer_lini, war_trasy, id_prz1, id_prz2
from alaska.trasa
where case when translate(numer_lini, '','0123456789') = ''
and numer_lini <> ''
then integer(numer_lini) else 0 end
between 100 and 999
Although that does fail if there is an embedded space in the input. E.g. '30 0'. To cater for that, a regular expressing is probably preferred. E.g.
select numer_lini, war_trasy, id_prz1, id_prz2
from alaska.trasa
where case when regexp_like(numer_lini, '^\s*[+-]?\s*((\d+\.?\d*)|(\d*\.?\d+))\s*$'))
then integer(numer_lini) else 0 end
between 100 and 999

CASE logic when removing NULLs

This is my first post, and I attempted to do a thorough search for this issue, so please accept my apologies if it has been posted elsewhere many times, but I'm wondering if anyone has encountered the following issue when attempting to remove NULLs from their result set:
case Occurrence
when NULL then '0'
else occurrence
end as Occurrence,
case Aggregate
when NULL then '0'
else Aggregate
end as Aggregate,
This didn't do anything to my NULLs; however, this did the trick:
case
when occurrence is NULL then '0'
else occurrence
end as Occurrence,
case
when aggregate is NULL then '0'
else Aggregate
end as Aggregate
Does anyone have any idea why this behaves this way? I'm using SQLServer2012.
I'm also not very versed in programming and only have less than a year SQL experience.
Thanks!
You should be using the ISNULL() or COALESCE() system function for handling nulls
something like
SELECT ISNULL(Occurrence , 0) AS Occurrence
,ISNULL(Aggregate , 0) AS Aggregate
FROM Table
OR
SELECT COALESCE(Occurrence , 0) AS Occurrence
,COALESCE(Aggregate , 0) AS Aggregate
FROM Table
The reason it didn't work in the case statement with
case Occurrence
when NULL then '0'
else occurrence
end as Occurrence,
is because it is interpreting it as
CASE
WHEN Occurrence = NULL THEN 0
ELSE Occurrence
END
Null is checked in sql server using IS NULL or IS NOT NULL if you use any other operator with null like = , <> or <, < it yields NULL hence the unexpected results.
Only for SQL Server 2012 and Later
In sql server 2012 and later versions you also have the IIF function
SELECT IIF(Occurrence IS NULL, 0, Occurrence) AS Occurrence
,IFF(Aggregate IS NULL , 0, Aggregate) AS Aggregate
FROM Table
You use simple case:
The simple CASE expression operates by comparing the first expression to the expression in each WHEN clause for equivalency. If these expressions are equivalent, the expression in the THEN clause will be returned.
Allows only an equality check.
case Occurrence
when NULL then '0'
else occurrence
end as Occurrence,
Which is executed as :
case
when occurence = NULL then '0'
else occurrence
end as Occurrence
Then expression occurence = NULL return NULL and is treated like False
Second your case use searched CASE with full condition and works fine:
case
when occurrence IS NULL then '0'
else occurrence
end as Occurrence,
So your question is about difference column IS NULL vs column = NULL
try
select 1 where null =null
select 1 where null is null
your statement looks like null equals null
select case when null is null then 1 else 0 end
select case null when null then 1 else 0 end
In your case use ISNULL this will give you the results your after
SELECT ISNULL(null,1)

sql records validation in a table

I like to check the length of a specified fields is x length and available value is a numeric value
i can do this by using two separate case statements like below
(case when len(columnA) = 10 then 0 else 1 end)+
(case when IsNumeric(columnA) = 1 then 0 else 1 end)+
(case when len(columnB) = 8 then 0 else 1 end)+
(case when IsNumeric(columnB) = 1 then 0 else 1 end)
is there any better approach as i need to this for more than 40 columns and their datatype is varchar and each of the column will have specific length.
using some short cut to reduce above two case statements into one line
If you only care that a column is invalid and are less interested in which criteria it failed on then you could just put both criteria into the one case statement as
(case when len(columnA) = 10 and IsNumeric(columnA) = 1 then 0 else 1 end)
In regards to the issue Sean raised, ISNUMERIC only confirms the value can be converted to a numeric datatype so commas and periods are valid too. you could do a check for any single character that isn't in the range of numbers
case when len(columnA) = 10 and ColumnA not like '%[^0-9]%' then 0 else 1 end
It is a little ugly because we have to say is not [not in range], so you might want to change the logic a bit.