SQL Server NULL Integer to Empty String using ISNULL - sql

My curiosity always gets the best of me and I've searched online for an explanation to this and came up with nothing (could be because I didn't use the right terms.)
Can someone please explain why SQL Server returns a value of zero (0) when the following is executed, instead of an empty string ('').
DECLARE #I AS INT
SET #I = NULL
SELECT ISNULL(#I, '') -- 0

As declared here, the second argument to ISNULL is the replacement_value, which "must be of a type that is implicitly convertible to the type of check_expresssion." Implicitly converting '' to INT results in 0.

Because #I is declared as an INT, the empty string is implicitly CAST as an integer resulting in a ZERO.

I know is an old question, but I want to share.
The issue here is not because the casting of the ' ' expression, is because the int data type is not null-able and, when you try to SET #I = NULL SQL set the default value zero(0).
That's why the statement ISNULL(#I, '') does not find any null in #I and returns its value(0).
Hope it helps somebody out there.

Related

Unpredictable behaviour in nested CASE statement

I'm unable to figure out why the control goes always to a statement irrespective of inside CASE condition.
A normal SQL statement works, but with my table it does not work.
--Not working--
SELECT
CASE WHEN [INTERNALDESCRIPTION] IS NOT NULL THEN --INTERNALDESCRIPTION IS A TEXT FIELD
CASE WHEN 'INT' = 'INT' THEN -- Or 'TEXT' = 'INT'
REPLACE( CONVERT(VARCHAR(MAX),[INTERNALDESCRIPTION] ) ,'''','') --should have come here
ELSE
REPLACE( CONVERT(INT,[INTERNALDESCRIPTION] ) ,'''','' ) -- Always comes here no matter what condition
END
ELSE
'NULL'
END
FROM DBO.RESOURCESTRINGMASTER WITH(NOLOCK) WHERE 1=1
-------working--
DECLARE #VALUE1 AS varchar(max) = '1Test', #VALUE2 AS VARCHAR(MAX) = '2'
SELECT
CASE WHEN #VALUE1 IS NOT NULL THEN
CASE WHEN 'INT' = 'INT' THEN
REPLACE( CONVERT(VARCHAR(MAX),#VALUE1 ) ,'''','')
ELSE
REPLACE( CONVERT(INT,#VALUE2 ) ,'''','' )
END
ELSE
'NULL'
END
And results in below error:
Explicit conversion from data type text to int is not allowed.
Explicit conversion from data type text to int is not allowed.
This error message seems pretty clear. Why are you using a text data type? It is deprecated. To quote from the documentation:
IMPORTANT! ntext, text, and image data types will be removed in a future version of SQL Server. Avoid using these data types in new development work, and plan to modify applications that currently use them. Use nvarchar(max), varchar(max), and varbinary(max) instead.
So, your code on the real table is executing the ELSE condition, which causes it to fail. In the code with constants, ELSE condition is not failing. Why is this?
I think the error is being caught in the compilation phase of the query. The error does not occur in the second example, because SQL Server is short-circuiting the query, recognizing that the ELSE is not needed. The code in the second example is simply not compiled.
I am pretty sure you would see the same behavior if you replaced the code with 1 / 0 (although the other part of the case expression would need to change as well for the types to be compatible).
It is not running the statement, it is failing because it sees something illegal.
If you want to see it on the other case change this line
DECLARE #VALUE1 AS varchar(max) = '1Test', #VALUE2 AS VARCHAR(MAX) = '2'
to
DECLARE #VALUE1 AS TEXT = '1Test', #VALUE2 AS VARCHAR(MAX) = '2'
You are comparing different test cases -- the first is not using VARCHAR

using parameters with max len and check for null vall

I'm trying to get a count for a column to see the max characters. I'm getting a warning, I know it doesn't effect, but it's more of an annoyance and would like to eliminate the warning.
My example is as follows:
Declare #Countthis varchar (255)
select #Counthis = max(len(col1)) from #temp
Print '------- This is the largest count for this column-----' + #Countthis
The warning I receive is:
Warning: Null value is eliminated by an aggregate or other SET operation.
I tried using Case statement but I couldn't figure it out. If the value is NULL just ignore the value.
Is this possible?
You can use
Declare #Countthis varchar (255)
select #Counthis = max(len(IsNull(col1,''))) from #temp

SQL Server: ISNULL on uniqueidentifier

I am trying to compare a column col1 and a variable #myvar in a WHERE clause. Both usually contain GUIDs, but may also have NULL values.
I thought I could get around the fact that NULL=NULL evaluates to FALSE by using WHERE ISNULL(col1, '')=ISNULL(#myvar, ''). That would compare two empty strings instead, and evaluate to TRUE.
This will, however, produce the following error message:
Msg 8169, Level 16, State 2, Line 3 Conversion failed when converting
from a character string to uniqueidentifier.
I tried
DECLARE #myvar uniqueidentifier = NULL
SELECT ISNULL(#myvar,'') as col1
Same error message.
Two questions:
First, I am trying to convert a uniqueidentifier variable - even though it has a NULL value - to an (empty!) string, not the other way around, as the error message suggests. What gives?
Second, is there a better way to word that WHERE clause I need, to allow for comparing uniqueidentifiers that might be NULL?
I think below expression can be used to check if the GUID column is empty
CAST(0x0 AS UNIQUEIDENTIFIER)
some thing like
...WHERE GuidId <> CAST(0x0 AS UNIQUEIDENTIFIER)
Since the first argument you are passing isnull is not a literal null, it will determine the return type of that call, a uniqueidentifier in your case. The second argument, '', cannot be cast to this type, hence the error you're getting.
One way around this is just to explicitly check for nulls:
WHERE (#myvar IS NULL AND col1 IS NULL) OR (col1 = #myvar)
The reason ISNULL isn't working for you is that the replacement value (the value to be used if the check expression really is null) must be implicitly convertible to the type of the check expression.
Your WHERE clause can use a col IS NULL AND #var IS NULL to check that state.
As others have pointed out, exclude the NULL values from the results and THEN do the comparison. You can use COALESCE to exclude NULL values from comparisons.
Try the following code:
WHERE ISNULL([Guid], NEWID()) = #myvar
Here is another way to overcome this issue:
DECLARE #myvar uniqueidentifier = NEWID()
SELECT * FROM TABLE
Where ISNULL(col1,#myvar) = ISNULL(Col2,#myvar)
This will resolve your error. Conversion failed when converting from a character string to uniqueidentifier.
I needed something similar on a where clause to compare 2 fields.
Declaring a uniqueidentifier variable is causing performance issues.
So I've used something like this.
WHERE COALESCE(Table1.Field1, CAST('00000000-0000-0000-0000-000000000000' AS UNIQUEIDENTIFIER))=COALESCE(Table2.Field2, CAST('00000000-0000-0000-0000-000000000000' AS UNIQUEIDENTIFIER))

Difficulty printing one particular query in MSSQL

I'm trying to construct a small query which will pull data from individual fields in a DB and print them in a human readable list format (it's what the operators are used to seeing). The code I have here is far from complete but It seems to me that it should work.
DECLARE #PSUCARD VARCHAR(20)
DECLARE #EQUIPMENT VARCHAR(50)
DECLARE #T1 VARCHAR
SET #PSUCARD = 'PSU-888'
SET #EQUIPMENT = '123_POUCH'
PRINT #PSUCARD + ':'
PRINT #EQUIPMENT
PRINT ''
IF (SELECT TEMPERATURE_MAIN FROM PSU WHERE PSU.PART_ID = #PSUCARD AND PSU.OPERATION_RESOURCE_ID = #EQUIPMENT)IS NOT NULL BEGIN
SET #T1 = (SELECT TEMPERATURE_MAIN FROM PSU WHERE PSU.PART_ID = #PSUCARD AND PSU.OPERATION_RESOURCE_ID = #EQUIPMENT)
PRINT 'Temperature: ' + #T1
--(SELECT TEMPERATURE_MAIN FROM PSU WHERE PSU.PART_ID = #PSUCARD AND PSU.OPERATION_RESOURCE_ID = #EQUIPMENT)
END
If I execute the code as is, #T1 returns a * rather than a value. If I remove comments from the line below I am reassured that there is indeed a value there.
I have other code very similar to this which works fine. Any ideas?
Also, I don't know if this helps in diagnosing the problem, but despite the temperature field in the DB being an INT, I get a conversion message if I try to treat #T1 an an INT.
This is because you declared #T1 as VARCHAR without a length. According to this:
When n is not specified in a data definition or variable declaration
statement, the default length is 1. When n is not specified when using
the CAST and CONVERT functions, the default length is 30.
You should always specify a length when declaring a VARCHAR variable:
DECLARE #T1 VARCHAR(50)
You need to give length for varchar datatype else it is going to take only one character
DECLARE #T1 VARCHAR(50)

SQL: SELECT number text base on a number

Background: I have an SQL database that contain a column (foo) of a text type and not integer. In the column I store integer in a text form.
Question: Is it possible to SELECT the row that contains (in foo column) number greater/lesser than n?
PS: I have a very good reason to store them as text form. Please refrain from commenting on that.
Update: (Forgot to mention) I am storing it in SQLite3.
SELECT foo
FROM Table
WHERE CAST(foo as int)>#n
select *
from tableName
where cast(textColumn as int) > 5
A simple CAST in the WHERE clause will work as long as you are sure that the data in the foo column is going to properly convert to an integer. If not, your SELECT statement will throw an error. I would suggest you add an extra step here and take out the non-numeric characters before casting the field to an int. Here is a link on how to do something similar:
http://blog.sqlauthority.com/2007/05/13/sql-server-udf-function-to-parse-alphanumeric-characters-from-string/
The only real modification you would need to do on this function would be to change the following lines:
PATINDEX('%[^0-9A-Za-z]%', #string)
to
PATINDEX('%[^0-9]%', #string)
The results from that UDF should then be castable to an int without it throwing an error. It will further slow down your query, but it will be safer. You could even put your CAST inside the UDF and make it one call. The final UDF would look like this:
CREATE FUNCTION dbo.UDF_ParseAlphaChars
(
#string VARCHAR(8000)
)
RETURNS int
AS
BEGIN
DECLARE #IncorrectCharLoc SMALLINT
SET #IncorrectCharLoc = PATINDEX('%[^0-9]%', #string)
WHILE #IncorrectCharLoc > 0
BEGIN
SET #string = STUFF(#string, #IncorrectCharLoc, 1, '')
SET #IncorrectCharLoc = PATINDEX('%[^0-9]%', #string)
END
SET #string = #string
RETURN CAST(#string as int)
END
GO
Your final SELECT statement would look something like this:
SELECT *
FROM Table
WHERE UDF_ParseAlphaChars(Foo) > 5
EDIT
Based upon the new information that the database is SQLite, the above probably won't work directly. I don't believe SQLite has native support for UDFs. You might be able to create a type of UDF using your programming language of choice (like this: http://www.christian-etter.de/?p=439)
The other option I see to safely get all of your data (an IsNumeric would exclude certain rows from your results, which might not be what you want) would probably be to create an extra column that has the int representation of the string. It is a little more dangerous in that you need to keep two fields in sync, but it will allow you to quickly sort and filter the table data.
SELECT *
FROM Table
WHERE CAST(foo as int) > 2000