IsNull() on bigint's min value? - sql

Why does the following expression in SQL Server return -9223372036854775808 and not 123?
I am calling this from a stored proc where I can't pass null parameters
declare #t bigint;
set #t = -9223372036854775808; --min value for bigint / long
select ISNULL(#t, 123)

Because:
IF #t IS NOT NULL
PRINT #t
ELSE
PRINT 123
Being negative doesn't mean the value is NULL. NULL is the lack of any value at all.

Because #t is not null.
What made you think that the most negative value for a bigint would be interpreted as null?

The ISNULL(#t, 123) function returns 123 if #t is NULL, otherwise it returns #t. You may want to do something like this.
NULLIF(#t, -9223372036854775808)
This will return NULL if #t equals -9223372036854775808. NULLIF returns the first expression (#t) if the two expressions are not equal.

To achieve what I think you want to achieve, try this:
declare #t bigint;
set #t = -9223372036854775808; --min value for bigint / long
select ISNULL(NULLIF(#t, -9223372036854775808) , 123)
or this:
declare #t bigint;
set #t = -9223372036854775808; --min value for bigint / long
select case #t when -9223372036854775808 then 123 else #t end

You seem to be assuming that -9223372036854775808 IS NULL which is incorrect. ISNULL(#t, 123) would only return NULL if #t IS NULL but it's not null since it has the value of -9223372036854775808 which is non-NULL.

ISNULL returns the first non-null value, they are both non-null (have value) so it returns the first one.

#t is not null because you assigned it a value. If you want ISNULL() to return 123, remove the assignment.
declare #t bigint;
select ISNULL(#t, 123)

Related

SQL Server 2014: How to cast a string value to int only if the value can be casted?

I try to cast a string value in a field of a table to int, but only in the case that the value stores a value that can be casted to int (in the other case the original value must be returned). Example:
DECLARE #ErrorCode nvarchar(1024)
SET #ErrorCode = 'a10'
SELECT IIF(TRY_CAST(#ErrorCode AS int) IS NULL, #ErrorCode, CAST(#ErrorCode AS int))
I've seen similar codes on StackOverflow.
My problem is that the SQL Server (2014) does not seem to short-circuit, and executes the cast always, even if TRY_CAST(#ErrorCode AS int) results in NULL. The result of the code above is the error "Conversion failed when converting the nvarchar value 'a10' to data type int."
See this sample on rextester.com
I also tried other variants with the same result:
SELECT CASE WHEN TRY_CAST(#ErrorCode AS int) IS NULL THEN #ErrorCode ELSE (SELECT CAST(#ErrorCode AS int)) END
SELECT CASE TRY_CAST(#ErrorCode AS int) WHEN 1 THEN CAST(#ErrorCode AS int) ELSE #ErrorCode END
How can I achieve my goal (avoid the cast in case the value in #ErrorCode cannot be casted)?
The simple solution would be to use COALSECE:
DECLARE #ErrorCode nvarchar(1024)
SET #ErrorCode = 'a10'
SELECT COALSECE(CAST(TRY_CAST(#ErrorCode AS int) as nvarchar(1024)), #ErrorCode)
However, I don't see the point of casting to int and then back to nvarchar.
To validate NULL you should IS NULL
DECLARE #ErrorCode NVARCHAR(1024)
SET #ErrorCode = 'a10'
SELECT IIF(TRY_CAST(#ErrorCode AS int) IS NULL, #ErrorCode, CAST(CAST(#ErrorCode AS int) AS VARCHAR(50)))
You need to convert the INT again to VARCHAR again to avoid the implicit conversion. IIF returns the data type with the highest precedence from the types in true_value and false_value.
The problem I see is trying to hold 2 different types in a single column. I'm not sure how you plan to use this information, but you could split the values in to numeric and text columns based on the type. You can do an ISNUMERIC() check and CAST to INT if it's true, otherwise leave it as text, like so:
CREATE TABLE #ErrorCodes ( ErrorCode NVARCHAR(10) )
INSERT INTO #ErrorCodes
( ErrorCode )
VALUES ( '123' ),
( 'a10' ),
( 'bbb' ),
( '456' )
SELECT ErrorCode AS OriginalVal ,
CASE WHEN ISNUMERIC(ErrorCode) = 1 THEN CAST(ErrorCode AS INT)
ELSE NULL
END AS NumericVal ,
CASE WHEN ISNUMERIC(ErrorCode) = 0 THEN ErrorCode
ELSE NULL
END AS NonNumericVal
FROM #ErrorCodes
DROP TABLE #ErrorCodes
Produces:
OriginalVal NumericVal NonNumericVal
=====================================
123 123 NULL
a10 NULL a10
bbb NULL bbb
456 456 NULL

Why the output is changed when using case statement?

Can anyone explain the Result?
DECLARE #dec AS VARCHAR(5)
SET #dec = 'Yes'
DECLARE #val DECIMAL(15, 2);
SET #val = - 34152542256.86;
SELECT #val as c1
,CAST(#val AS BIGINT) as c2
SELECT #val as c1
,CASE #dec
WHEN 'Yes'
THEN CAST(#val AS BIGINT)
ELSE #val
END as c2
Results:
of first select statement:
c1 c2
-34152542256.86 -34152542256
of second select statement:
c1 c2
-34152542256.86 -34152542256.00
Source
You have an implicit conversion in your CASE statement. Basically, c2 must have a data-type, but SQL Server doesn't know whether it's DECIMAL(15,2) or BIGINT, as both types are returned from the various branches through the CASE statement. The rules of data-type precedence kick in and c2 ends up being converted to a DECIMAL(15,2).
As a try and I think this could work in this case, try sql_variant data-type like this:
DECLARE #val sql_variant;
In the first select statement the result for c2 can only be BIGINT.
In the second statement the result can be BIGINT or DECIMAL(15,2), belongs to which branch of case statement is entered. Since you can't have mixed types in one column sql server automatically converts c2 to DECIMAL(15,2)
BIGINT is an integer value (it does not allow scale), try using DECIMAL or NUMERIC.
And don't give up reading documentation.

SQL SERVER: Check if variable is null and then assign statement for Where Clause

I am trying to achieve something like the below in WHERE clause in sql.
if (#zipCode ==null)
begin
([Portal].[dbo].[Address].Position.Filter(#radiusBuff) = 1)
end
else if(#zipCode !=null)
begin
([Portal].[dbo].[Address].PostalCode=#zipCode )
end
I tried the following:
WHERE ((#zipCode IS NOT NULL AND ([Portal].[dbo].[Address].PostalCode=#zipCode)) OR (#zipCode IS NULL AND ([Portal].[dbo].[Address].Position.Filter(#radiusBuff) = 1)))
which is wrong. Can anyone help in framing the exact statement. Thanks!
is null is the syntax I use for such things, when COALESCE is of no help.
Try:
if (#zipCode is null)
begin
([Portal].[dbo].[Address].Position.Filter(#radiusBuff) = 1)
end
else
begin
([Portal].[dbo].[Address].PostalCode=#zipCode )
end
Isnull() syntax is built in for this kind of thing.
declare #Int int = null;
declare #Values table ( id int, def varchar(8) )
insert into #Values values (8, 'I am 8');
-- fails
select *
from #Values
where id = #Int
-- works fine
select *
from #Values
where id = isnull(#Int, 8);
For your example keep in mind you can change scope to be yet another where predicate off of a different variable for complex boolean logic. Only caveat is you need to cast it differently if you need to examine for a different data type. So if I add another row but wish to specify int of 8 AND also the reference of text similar to 'repeat' I can do that with a reference again back to the 'isnull' of the first variable yet return an entirely different result data type for a different reference to a different field.
declare #Int int = null;
declare #Values table ( id int, def varchar(16) )
insert into #Values values (8, 'I am 8'), (8, 'I am 8 repeat');
select *
from #Values
where id = isnull(#Int, 8)
and def like isnull(cast(#Int as varchar), '%repeat%')
is null can be used to check whether null data is coming from a query as in following example:
declare #Mem varchar(20),#flag int
select #mem=MemberClub from [dbo].[UserMaster] where UserID=#uid
if(#Mem is null)
begin
set #flag= 0;
end
else
begin
set #flag=1;
end
return #flag;
Try a case statement
WHERE
CASE WHEN #zipCode IS NULL THEN 1
ELSE #zipCode
END
Try the following:
if ((select VisitCount from PageImage where PID=#pid and PageNumber=5) is NULL)
begin
update PageImage
set VisitCount=1
where PID=#pid and PageNumber=#pageno
end
else
begin
update PageImage
set VisitCount=VisitCount+1
where PID=#pid and PageNumber=#pageno
end

ISNULL function in SQL Server 2008 not working properly

Assume this script:
DECLARE #result TABLE(Id BIGINT);
DELETE FROM [Products].[Product]
OUTPUT DELETED.[Id] INTO #result
WHERE [Products].[Product].[Id] = 1589;
So in continues I try :
1
SELECT CAST(ISNULL([Id], -1) AS BIGINT) AS N'RetValId' FROM #result;
When [Id] is null returned null (nothing), but this one returned -1:
2
DECLARE #mi BIGINT;
SET #mi = (SELECT [Id] FROM #result)
SELECT CAST(ISNULL(#mi, -1) AS BIGINT) AS N'RetValId'
Why? where is the problem with first script?
Update
So is there any way to check if the Deleted Id is null returned -1 And if not Returned Id without declare another variable? what is the simplest way?
If you have no entry for the ID 1589, then in the DELETED table there will be no record, if you have it then it should return 1589.
So if you don't have I think it simple returns nothing, because this statement has no input row:
SELECT CAST(ISNULL([Id], -1) AS BIGINT) AS N'RetValId' FROM #result;
(If you SELECT * from #result it should be no rows there)
The second one return the -1 because you set first to the variable which is getting the NULL value after the select.
DECLARE #mi BIGINT;
SET #mi = (SELECT [Id] FROM #result)
(If you select only #mi after this, then it should be NULL)
I think that is the explanation
UPDATED:
May you can try a small trick to achive it without an other varriable:
SELECT CAST(ISNULL(MAX([ID]),-1) AS BIGINT) AS N'RetValId' FROM #result;
Because of MAX the insie statement will be NULL, so here is the trick. If something was deleted, then the ID will be there.
I hope it helped.
You can use a derived table that will return one row with -1 and then do an outer apply on #result.
select isnull(R.Id, T.Id) RetValId
from (values(-1)) as T(Id)
outer apply #result as R
An easy way to return null if no rows where deleted is the ##rowcount variable. It contains the number of rows affected by the previous operation:
DELETE FROM [Products].[Product]
WHERE [Products].[Product].[Id] = 1589;
IF ##ROWCOUNT = 0
return null
return 1589

SQL Server AVG function to return NULL if all values are NULL

I have a table similar to this
+--+-----+----+
|ID|Entry|Exit|
+--+-----+----+
|18|32154|NULL|
+--+-----+----+
|19|NULL |NULL|
+--+-----+----+
When I select AVG(Entry) it correctly gives me 32154, when I select AVG(Exit) it blows up saying "Operand data type void type is invalid for avg operator."
How can I get NULL as the average for a column that only has NULL values?
Thanks,
Try using CASE like this
SELECT CASE WHEN SUM(Exit) IS NULL THEN NULL ELSE AVG(Exit) END AS MyAverage
FROM MyTable
I think The problem is with the column name. Just change the column name to ExitCol and check.
In that case even SELECT AVG(ExitCol) AS MyAverage FROM MyTable also will work
The problem is that the Exit column doesn't have a data type that is compatible with the SUM function.
You can run this query to see that you indeed get NULL from SUM if all values are NULL (and a proper data type)
select sum(a) from (select convert(int, null) a union select null) a
Select avg(isnull(Exit,0)) from table
use set xact_abort off to get it to return null
declare #a table (id int, amount numeric(10,2))
insert into #a values (1, null), (2,null), (3,null)
set xact_abort off
select AVG(amount)
from #a