SELECT CASE WHEN TINYINT field condition met return string - sql

I am using SQL Server 2005. I am trying to do a select from a TINYINT field. If the field's value is 0 I want to select an empty string instead ' ' . The fields name is level. HEre is what I am doing:
SELECT
[Level] =
Case
t.[Level]
WHEN 0 THEN ' '
ELSE t.[Level]
END
FROM table t
This code always returns 0. I was trying to troubleshoot the issue and tried this:
SELECT
[Level] =
Case
t.[Level]
WHEN 0 THEN 'test'
ELSE t.[Level]
END
FROM table t
And I got a the error Conversion failed when converting the varchar value 'test' to data type tinyint
So I'm seeing that there is a conversion problem here. I've tried:
SELECT
[Level] =
Case
t.[Level]
WHEN 0 THEN CONVERT(VARCHAR,t.[level])
ELSE t.[Level]
END
FROM table t
But this of course still returns 0, just the character, so it's still not doing what I need. I am thinking that there is most likely a better way to do this but am not sure how to approach it. Could anyone give me some advice on how to handle this? Thanks much!

For CASE statements, all returned values must be of the same type (or automatically convertable); that's the reason why '' was working, but 'test' wasn´t.
SELECT [Level] =
Case t.[Level]
WHEN 0 THEN ' '
ELSE CONVERT(VARCHAR(3), t.[Level])
END
FROM table t

Your attempt to fix this went the wrong way; you needed to convert the else portion to a varchar to match the varchar empty string:
SELECT
[Level] =
Case
t.[Level]
WHEN 0 THEN ''
ELSE CAST(t.[Level] AS VARCHAR(10))
END
FROM table t

Related

SQL COALESCE and IS NULL are not returning a space when when the query returns NULL

I am trying to optimize a humongous SQL query that was written by a self taught developer that used a ton of functions instead of JOINS. Anyway, I am having trouble displaying a space or a empty string('') when there is no value in the field selected. I've included only the SELECT in question. I am having the weirdest problem or just overlooking the correct answer in troubleshooting. Whenever I use COALESCE, when the field is supposed to be a blank string, it displays a zero. And when I use IS NULL, I get back NULL. All info online seems to point toward using COALESCE(value, '') as depicted in the code. But I am getting a 0 instead of ''. Does anyone see what I'm doing wrong? I'm using SSMS.
SELECT
pss8.dbo.xml_StripIllegalChars(dbo.rpt_get_series_volume(b.bookkey)) AS p_seriesvol --SELECT to be replaced that works but is slow due to function use I am told
,COALESCE(bd.seriesvolume, '') AS p_seriesvol --my SELECT that won't work!
FROM
bookdetail bd
WHERE
--bd.bookkey='303177'
bd.bookkey='6002'
The bookkeys at the bottom are for testing as I know the top one returns a 1 and the bottom one returns a '' previously when it worked. The SELECT above my commented SELECT is the code that works but is slow... According to what I read online, I am saying 'if there isn't a series volume number, then it equals an empty string.' Does COALESCE not work like this? Can it only return a 0 if the field has no value, or in this case, has no volume number? All help much appreciated. I'm very curious to hear a solution!
Here's more intel. This is how the this SELECT works:
pss8.dbo.xml_StripIllegalChars(dbo.rpt_get_series_volume(b.bookkey)) AS p_seriesvol
The
.rpt_get_series_vol
function manages to create an empty string with this code... Does this reveal anything?
DECLARE #RETURN
VARCHAR(5)
DECLARE #v_desc
VARCHAR(5)
DECLARE #i_volumenumber INT
SELECT #i_volumenumber = volumenumber
FROM bookdetail
WHERE bookkey = #i_bookkey and volumenumber <> 0
IF #i_volumenumber > 0
BEGIN
SELECT #RETURN = CAST(#i_volumenumber as varchar(5))
END
ELSE
BEGIN
SELECT #RETURN = ''
END
RETURN #RETURN
END
As you are looking for a '0' not a NULL COALESCE()is not useful, instead use a simple CASE:
select
...,
case bd.seriesvolume when '0' then '' else bd.seriesvolume end as p_seriesvol
from
...
Or if you want '' for 0 or NULL
case when bd.seriesvolume is null or bd.seriesvolume = '0' then '' else bd.seriesvolume end as p_seriesvo
COALESCE() function returns the 1st non null value
SELECT COALESCE(NULL, NULL, 'third_value', 'fourth_value'); returns the third value because the third value is the first value that is not null.
So in your case COALESCE(bd.seriesvolume, '') AS p_seriesvol if seriesvolume colum value is null then it will return blank string

ISNUMERIC and TRY_PARSE in SQL Server [duplicate]

What is the best way to determine whether or not a field's value is an integer in SQL Server (2000/2005/2008)?
IsNumeric returns true for a variety of formats that would not likely convert to an integer. Examples include '15,000' and '15.1'.
You can use a like statement but that only appears to work well for fields that have a pre-determined number of digits...
select * where zipcode like '[0-9][0-9][0-9][0-9][0-9]'
I could write a user defined function that attempts to convert a varchar parameter to an int within a try/catch block but I'm checking with the community to see if someone has come across any succient methods to achieve this goal - preferably one that can be used within the where clause of a SQL statement without creating other objects.
Late entry that handles negative
ISNUMERIC(zipcode + '.0e0') --integer
ISNUMERIC(zipcode + 'e0') --decimal
For more see this
1 approach is
zipcode NOT LIKE '%[^0-9]%'
Double negatives, got to love 'em!
If SQL Server 2005+, I'd enable CLR and create the function to support regexes. For SQL Server 2000, see this article for creating a UDF to do the same thing.
Then I'd use the regex: ^\d{5}$
This expression gives 1 for an integer value and 0 otherwise
floor((floor(abs(zipcode)))/abs(zipcode))
Why not just use the following? I can't see to find any cases where it fails.
1 = integer
0 = not integer
null = non-numeric
DECLARE #TestValue nvarchar(MAX)
SET #TestValue = '1.04343234e5'
SELECT CASE WHEN ISNUMERIC(#TestValue) = 1
THEN CASE WHEN ROUND(#TestValue,0,1) = #TestValue
THEN 1
ELSE 0
END
ELSE null
END AS Analysis
It looks like this question needs an updated answer.
Limiting the answer to the question title:
where ISNUMERIC(zipcode) = 1
and zipcode - FLOOR(zipcode) = 0
Expounding based on the text of the question...
Currently-supported versions of SQL Server all support/include the TRY-CONVERT function.
declare #a varchar(100)
set #a = '-1.2a'
--set #a = '-1.2'
--set #a = '-1'
--set #a = '-1.0'
--set #a = '-0'
--set #a = '0'
--set #a = '1'
select #a as 'Value'
, ISNUMERIC(#a) as ISNUMERIC
, case when ISNUMERIC(#a) = 1 and #a - FLOOR(#a) = 0 then 1 else 0 end as ISINTEGER
, case when try_convert(int, #a) >= 0 and left(#a, 1) <> '-' then 1 else 0 end as ISWHOLENUMBER
, case when try_convert(int, #a) > 0 then 1 else 0 end as ISCOUNTINGNUMBER
You'll notice that TRY_CONVERT(INT, -1.0) returns NULL. So TRY_CONVERT(INT, #a) IS NOT NULL is not quite right for ISINTEGER.
case when ISNUMERIC(#a) = 1 and #a - FLOOR(#a) = 0 then 1 else 0 end as ISINTEGER
...works because if ISNUMERIC(#a) = 1 is false, FLOOR(#a) is not evaluated. Reversing the order...
case when #a - FLOOR(#a) = 0 and ISNUMERIC(#a) = 1 then 1 else 0 end as ISINTEGER
...generates an error when the value (#a) is not numeric.
So, for the case of zipcode, assuming you want to verify that a 5-digit zip code is a number and it must be 5 digits (so it can't be zero or less) and would never contain a decimal point (so you don't need to know if 12345.000 is an integer):
where try_convert(int, zipcode) > 0
and len(zipcode) = 5
I came up with the perfect answer for this on another StackO question.
It also proves you cannot use ".0e0" like one user suggests here.
It does so without CLR or non-scalar functions.
Please check it out: https://stackoverflow.com/a/10645764/555798
After moving to sql 2008, I was struggling with isnumeric('\8') returning true but throwing an error when casting to an integer. Apparently forward slash is valid currency for yen or won - (reference http://www.louiebao.net/blog/200910/isnumeric/)
My solution was
case when ISNUMERIC(#str) > 0 and not rtrim(#str) LIKE '[^0-9]%' and not rtrim(#str) LIKE '%[^0-9]' and not rtrim(#str) LIKE '[^0-9]%' then rtrim(#str) else null end
See whether the below code will help.
In the below values only 9, 2147483647, 1234567 are eligible as
Integer. We can create this as function and can use this.
CREATE TABLE MY_TABLE(MY_FIELD VARCHAR(50))
INSERT INTO MY_TABLE
VALUES('9.123'),('1234567'),('9'),('2147483647'),('2147483647.01'),('2147483648'), ('2147483648ABCD'),('214,7483,648')
SELECT *
FROM MY_TABLE
WHERE CHARINDEX('.',MY_FIELD) = 0 AND CHARINDEX(',',MY_FIELD) = 0
AND ISNUMERIC(MY_FIELD) = 1 AND CONVERT(FLOAT,MY_FIELD) / 2147483647 <= 1
DROP TABLE MY_TABLE
I did it using a Case statement:
Cast(Case When Quantity/[# of Days]= Cast(Quantity/[# of Days] as int) Then abs(Quantity/[# of Days]) Else 0 End as int)
To test whether the input value is an integer or not we can use SQL_VARIANT_PROPERTY function of SQL SERVER.
The following SQL Script will take input and test it whether the data type turns out to be integer or not
declare #convertedTempValue bigint, #inputValue nvarchar(255) = '1' --Change '1' to any input value
set #convertedTempValue = TRY_PARSE(#inputValue as bigint) --we trying to convert to bigint
declare #var3 nvarchar(255) = cast (SQL_VARIANT_PROPERTY(#convertedTempValue,'BaseType') as nvarchar(255)) --we using SQL_VARIANT_PROPERTY to find out datatype
if ( #var3 like '%int%')
begin
print 'value is integer'
end
else
begin
print 'value is non integer'
end
go
Really late to this but would this work?
select * from from table
where (ISNUMERIC(zipcode) = 0 OR zipcode like '%.%')
Filters out items that are integers.
Maybe you should only store integer data in integer datatypes.

SQL - string comparison ignores space

This query:
SELECT CASE WHEN 'abc ' = 'abc' THEN 1 ELSE 0 END
Returns 1, even though 'abc ' clearly is not equal to 'abc'. Similarly,
SELECT CASE WHEN 'abc ' LIKE '%c' THEN 1 ELSE 0 END
Also returns 1. However, a very similar query:
SELECT * FROM #tempTable WHERE Name LIKE '%c'
Did not return a row where Name = 'abc '.
SQL Server 2008 R2, Windows 7 & 2008 R2, x64.
= ignores trailing space
len ignores training space
like does not ignore trailing space
SELECT CASE WHEN 'abc ' = 'abc' and DATALENGTH('abc ') = DATALENGTH('abc')
THEN 1 ELSE 0 END
You can assert DATALENGTH is not relevant but it is still the solution.
Turns out that the Name column was NVARCHAR (even though it contained ASCII characters only) and NVARCHAR behaves differently than VARCHAR:
SELECT CASE WHEN N'abc ' LIKE 'abc' THEN 1 ELSE 0 END
Returns 0, ditto for column instead of literal. The following does return 1 still:
SELECT CASE WHEN N'abc ' = 'abc' THEN 1 ELSE 0 END
So = and LIKE work differently, another peculiar difference.
If you need to compare things in this way but are restricted because your columns are of data type VARCHAR, something like this will basically fill the trailing space with an 'X' which will accomplish a failed comparison:
DECLARE #1 VARCHAR(5), #2 VARCHAR(5)
SET #1 = 'ABC '
SET #2 = 'ABC'
IF REPLACE(#1,' ','X') = REPLACE(#2,' ','X')
PRINT 'Equal'
ELSE
PRINT 'Not Equal'
Not rocket science, but at least a work around if you encounter a similar situation that you need to deal with :)
TA, I am not sure how you got zero by simply mentioning as unicode(N). I run your query and it giving me 1 only.
You can compare the LEN('abc ') and DATALENGTH('abc ') and can use those as per you requirement or you can replace the trailing space with some character to solve your problem.
I had a similar issue with a nvarchar column and wanted to fix the data so I did the following to find the data
select 'x' + username + 'x' from aspnet_users
where 'x' + username + 'x' <> 'x' + rtrim(username) + 'x'
The where clause compares the username as is with the trimmed version
'x1234 x' <> 'x1234x'
To fix the data I just did an update
update aspnet_Users
set username = rtrim(username)
where 'x' + username + 'x' <> 'x' + rtrim(username) + 'x'

TSQL CASE LTRIM (RTRIM NULL

SQL Syntax is still something I am learning. I am getting the error noted below the this snippet of code.
SELECT
CASE WHEN LTRIM(RTRIM(cLehmanNo)) =' ' THEN NULL
WHEN cLehmanNo IS NOT NULL THEN REPLACE ( cLehmanNo,SUBSTRING (cLehmanNo,PATINDEX( '%[^a-zA-Z0-9 '''''']%',cLehmanNo),1), ' ' )
END asLOAN_NUMBER
,CASE WHEN LTRIM(RTRIM(cMERS)) =' ' THEN NULL
WHEN cMERS IS NOT NULL THEN REPLACE ( cMERS,SUBSTRING (cMERS,PATINDEX( '%[^a-zA-Z0-9 '''''']%',cMERS),1), ' ' )
END asMERS_ID
and 100+ more of same.
Msg 8133, Level 16, State 1, Line 1
None of the result expressions in a CASE specification can be NULL.
What am I doing wrong? How do I keep the gist of the statement and not get this crazy error?
This happens when it can't infer the type.
e.g.
SELECT CASE WHEN 1 = 2 THEN NULL ELSE NULL END
But this works
SELECT CASE WHEN 1 = 2 THEN NULL ELSE replace(NULL,'','') END
so I doubt the error is from the code you have shown us (You are using string functions and the following quick test shows that it will assume that to be varchar(8000))
SELECT CASE WHEN 1 = 2 THEN NULL ELSE REPLACE(NULL,'','') END a
INTO t /*Creates column of datatype varchar(8000)*/
You need to convert NULL to a correct type matching the overall values, e.g. CONVERT(VARCHAR(10), NULL), otherwise the server can't deduce which type to make the resulting value.
The error message actually means that all results in one of your case expressions are null. You have an expression like:
case when something then null when something then null end
At least one of the results has to be something other than null. You could circumvent this, but most likely there is a mistake in the query, as a case exression that always returns the same result is pointless.
The error message has been changed to:
At least one of the result expressions
in a CASE specification must be an
expression other than the NULL
constant.
SELECT
CASE WHEN LTRIM(RTRIM(cLehmanNo)) =' ' THEN NULL
WHEN cLehmanNo IS NOT NULL THEN REPLACE ( cLehmanNo,SUBSTRING (cLehmanNo,PATINDEX( '%[^a-zA-Z0-9 '''''']%',cLehmanNo),1), ' ' )
ELSE ''
END asLOAN_NUMBER
,CASE WHEN LTRIM(RTRIM(cMERS)) =' ' THEN NULL
WHEN cMERS IS NOT NULL THEN REPLACE ( cMERS,SUBSTRING (cMERS,PATINDEX( '%[^a-zA-Z0-9 '''''']%',cMERS),1), ' ' )
ELSE ''
END asMERS_ID

Best equivalent for IsInteger in SQL Server

What is the best way to determine whether or not a field's value is an integer in SQL Server (2000/2005/2008)?
IsNumeric returns true for a variety of formats that would not likely convert to an integer. Examples include '15,000' and '15.1'.
You can use a like statement but that only appears to work well for fields that have a pre-determined number of digits...
select * where zipcode like '[0-9][0-9][0-9][0-9][0-9]'
I could write a user defined function that attempts to convert a varchar parameter to an int within a try/catch block but I'm checking with the community to see if someone has come across any succient methods to achieve this goal - preferably one that can be used within the where clause of a SQL statement without creating other objects.
Late entry that handles negative
ISNUMERIC(zipcode + '.0e0') --integer
ISNUMERIC(zipcode + 'e0') --decimal
For more see this
1 approach is
zipcode NOT LIKE '%[^0-9]%'
Double negatives, got to love 'em!
If SQL Server 2005+, I'd enable CLR and create the function to support regexes. For SQL Server 2000, see this article for creating a UDF to do the same thing.
Then I'd use the regex: ^\d{5}$
This expression gives 1 for an integer value and 0 otherwise
floor((floor(abs(zipcode)))/abs(zipcode))
Why not just use the following? I can't see to find any cases where it fails.
1 = integer
0 = not integer
null = non-numeric
DECLARE #TestValue nvarchar(MAX)
SET #TestValue = '1.04343234e5'
SELECT CASE WHEN ISNUMERIC(#TestValue) = 1
THEN CASE WHEN ROUND(#TestValue,0,1) = #TestValue
THEN 1
ELSE 0
END
ELSE null
END AS Analysis
It looks like this question needs an updated answer.
Limiting the answer to the question title:
where ISNUMERIC(zipcode) = 1
and zipcode - FLOOR(zipcode) = 0
Expounding based on the text of the question...
Currently-supported versions of SQL Server all support/include the TRY-CONVERT function.
declare #a varchar(100)
set #a = '-1.2a'
--set #a = '-1.2'
--set #a = '-1'
--set #a = '-1.0'
--set #a = '-0'
--set #a = '0'
--set #a = '1'
select #a as 'Value'
, ISNUMERIC(#a) as ISNUMERIC
, case when ISNUMERIC(#a) = 1 and #a - FLOOR(#a) = 0 then 1 else 0 end as ISINTEGER
, case when try_convert(int, #a) >= 0 and left(#a, 1) <> '-' then 1 else 0 end as ISWHOLENUMBER
, case when try_convert(int, #a) > 0 then 1 else 0 end as ISCOUNTINGNUMBER
You'll notice that TRY_CONVERT(INT, -1.0) returns NULL. So TRY_CONVERT(INT, #a) IS NOT NULL is not quite right for ISINTEGER.
case when ISNUMERIC(#a) = 1 and #a - FLOOR(#a) = 0 then 1 else 0 end as ISINTEGER
...works because if ISNUMERIC(#a) = 1 is false, FLOOR(#a) is not evaluated. Reversing the order...
case when #a - FLOOR(#a) = 0 and ISNUMERIC(#a) = 1 then 1 else 0 end as ISINTEGER
...generates an error when the value (#a) is not numeric.
So, for the case of zipcode, assuming you want to verify that a 5-digit zip code is a number and it must be 5 digits (so it can't be zero or less) and would never contain a decimal point (so you don't need to know if 12345.000 is an integer):
where try_convert(int, zipcode) > 0
and len(zipcode) = 5
I came up with the perfect answer for this on another StackO question.
It also proves you cannot use ".0e0" like one user suggests here.
It does so without CLR or non-scalar functions.
Please check it out: https://stackoverflow.com/a/10645764/555798
After moving to sql 2008, I was struggling with isnumeric('\8') returning true but throwing an error when casting to an integer. Apparently forward slash is valid currency for yen or won - (reference http://www.louiebao.net/blog/200910/isnumeric/)
My solution was
case when ISNUMERIC(#str) > 0 and not rtrim(#str) LIKE '[^0-9]%' and not rtrim(#str) LIKE '%[^0-9]' and not rtrim(#str) LIKE '[^0-9]%' then rtrim(#str) else null end
See whether the below code will help.
In the below values only 9, 2147483647, 1234567 are eligible as
Integer. We can create this as function and can use this.
CREATE TABLE MY_TABLE(MY_FIELD VARCHAR(50))
INSERT INTO MY_TABLE
VALUES('9.123'),('1234567'),('9'),('2147483647'),('2147483647.01'),('2147483648'), ('2147483648ABCD'),('214,7483,648')
SELECT *
FROM MY_TABLE
WHERE CHARINDEX('.',MY_FIELD) = 0 AND CHARINDEX(',',MY_FIELD) = 0
AND ISNUMERIC(MY_FIELD) = 1 AND CONVERT(FLOAT,MY_FIELD) / 2147483647 <= 1
DROP TABLE MY_TABLE
I did it using a Case statement:
Cast(Case When Quantity/[# of Days]= Cast(Quantity/[# of Days] as int) Then abs(Quantity/[# of Days]) Else 0 End as int)
To test whether the input value is an integer or not we can use SQL_VARIANT_PROPERTY function of SQL SERVER.
The following SQL Script will take input and test it whether the data type turns out to be integer or not
declare #convertedTempValue bigint, #inputValue nvarchar(255) = '1' --Change '1' to any input value
set #convertedTempValue = TRY_PARSE(#inputValue as bigint) --we trying to convert to bigint
declare #var3 nvarchar(255) = cast (SQL_VARIANT_PROPERTY(#convertedTempValue,'BaseType') as nvarchar(255)) --we using SQL_VARIANT_PROPERTY to find out datatype
if ( #var3 like '%int%')
begin
print 'value is integer'
end
else
begin
print 'value is non integer'
end
go
Really late to this but would this work?
select * from from table
where (ISNUMERIC(zipcode) = 0 OR zipcode like '%.%')
Filters out items that are integers.
Maybe you should only store integer data in integer datatypes.