I want to return the records in this case that have company ABC... and contact is null. It will not return anything when #Contact is null. Or any variable for that matter. Ideas?
DECLARE #Customer NVARCHAR(40) = 'ABC Company',
#Contact NVARCHAR(40) = NULL
SELECT
Company
FROM
company
WHERE
contact = #Contact AND customer = #Customer
Thanks,
EB
NULL is special in that it means UNKNOWN.
A known value (contact) can never equal an unknown value. You need an OR statement to check if it's equal OR is null
where (contact = #Contact OR (contact is null AND #Contact is null))
and customer = #Customer
Maybe something like that?
you can write
WHERE
ISNULL(contact,'') = ISNULL(#Contact,'') AND customer = #Customer
this do a null check and if null,then value will be considered as empty string for comparison.
instead of null==null (Which gives false), ''=='' will be performed.
if(null =null)
print 'Equal'
else
print 'not equal'
/*******************************************/
if('' ='')
print 'Equal'
else
print 'not equal'
In SQL, there is trivalent logic applied. In this reference you can read in detail about such logic. Bottom line is, that among true and false, there is another value: UNKNOWNN, which (in SQL) is the result of comparisons with NULL values. You can think of it as false (in this case).
Now, to visualise:
this queries won't return anything, as the where clause evaluates to UNKNOWN:
select 1 where null = 0
select 1 where null <> 0
select 1 where null = null
While this might be obvious, there's consequence: when you use not in operator.
When right operand contains NULLs, the query will return no records, e.g.:
select 1 where 0 not in (null, 1, 2)
won't return anything. It's especially important when you put some query as right operand.
Related
Could someone please explain the following behavior in SQL?
SELECT * FROM MyTable WHERE MyColumn != NULL (0 Results)
SELECT * FROM MyTable WHERE MyColumn <> NULL (0 Results)
SELECT * FROM MyTable WHERE MyColumn IS NOT NULL (568 Results)
<> is Standard SQL-92; != is its equivalent. Both evaluate for values, which NULL is not -- NULL is a placeholder to say there is the absence of a value.
Which is why you can only use IS NULL/IS NOT NULL as predicates for such situations.
This behavior is not specific to SQL Server. All standards-compliant SQL dialects work the same way.
Note: To compare if your value is not null, you use IS NOT NULL, while to compare with not null value, you use <> 'YOUR_VALUE'. I can't say if my value equals or not equals to NULL, but I can say if my value is NULL or NOT NULL. I can compare if my value is something other than NULL.
NULL has no value, and so cannot be compared using the scalar value operators.
In other words, no value can ever be equal to (or not equal to) NULL because NULL has no value.
Hence, SQL has special IS NULL and IS NOT NULL predicates for dealing with NULL.
Note that this behavior is the default (ANSI) behavior.
If you:
SET ANSI_NULLS OFF
http://msdn.microsoft.com/en-us/library/ms188048.aspx
You'll get different results.
SET ANSI_NULLS OFF will apparently be going away in the future...
We use
SELECT * FROM MyTable WHERE ISNULL(MyColumn, ' ') = ' ';
to return all rows where MyColumn is NULL or all rows where MyColumn is an empty string. To many an "end user", the NULL vs. empty string issue is a distinction without a need and point of confusion.
In SQL, anything you evaluate / compute with NULL results into UNKNOWN
This is why SELECT * FROM MyTable WHERE MyColumn != NULL or SELECT * FROM MyTable WHERE MyColumn <> NULL gives you 0 results.
To provide a check for NULL values, isNull function is provided.
Moreover, you can use the IS operator as you used in the third query.
The only test for NULL is IS NULL or IS NOT NULL. Testing for equality is nonsensical because by definition one doesn't know what the value is.
Here is a wikipedia article to read:
https://en.wikipedia.org/wiki/Null_(SQL)
NULL Cannot be compared to any value using the comparison operators. NULL = NULL is false. Null is not a value. The IS operator is specially designed to handle NULL comparisons.
null represents no value or an unknown value. It doesn’t specify why there is no value, which can lead to some ambiguity.
Suppose you run a query like this:
SELECT *
FROM orders
WHERE delivered=ordered;
that is, you are looking for rows where the ordered and delivered dates are the same.
What is to be expected when one or both columns are null?
Because at least one of the dates is unknown, you cannot expect to say that the 2 dates are the same. This is also the case when both dates are unknown: how can they be the same if we don’t even know what they are?
For this reason, any expression treating null as a value must fail. In this case, it will not match. This is also the case if you try the following:
SELECT *
FROM orders
WHERE delivered<>ordered;
Again, how can we say that two values are not the same if we don’t know what they are.
SQL has a specific test for missing values:
IS NULL
Specifically it is not comparing values, but rather it seeks out missing values.
Finally, as regards the != operator, as far as I am aware, it is not actually in any of the standards, but it is very widely supported. It was added to make programmers from some languages feel more at home. Frankly, if a programmer has difficulty remembering what language they’re using, they’re off to a bad start.
I would like to suggest this code I made to find if there is a change in a value,
i being the new value and d being the old (although the order does not matter). For that matter, a change from value to null or vice versa is a change but from null to null is not (of course, from value to another value is a change but from value to the same it is not).
CREATE FUNCTION [dbo].[ufn_equal_with_nulls]
(
#i sql_variant,
#d sql_variant
)
RETURNS bit
AS
BEGIN
DECLARE #in bit = 0, #dn bit = 0
if #i is null set #in = 1
if #d is null set #dn = 1
if #in <> #dn
return 0
if #in = 1 and #dn = 1
return 1
if #in = 0 and #dn = 0 and #i = #d
return 1
return 0
END
To use this function, you can
declare #tmp table (a int, b int)
insert into #tmp values
(1,1),
(1,2),
(1,null),
(null,1),
(null,null)
---- in select ----
select *, [dbo].[ufn_equal_with_nulls](a,b) as [=] from #tmp
---- where equal ----
select *,'equal' as [Predicate] from #tmp where [dbo].[ufn_equal_with_nulls](a,b) = 1
---- where not equal ----
select *,'not equal' as [Predicate] from #tmp where [dbo].[ufn_equal_with_nulls](a,b) = 0
The results are:
---- in select ----
a b =
1 1 1
1 2 0
1 NULL 0
NULL 1 0
NULL NULL 1
---- where equal ----
1 1 equal
NULL NULL equal
---- where not equal ----
1 2 not equal
1 NULL not equal
NULL 1 not equal
The usage of sql_variant makes it compatible for variety of types
NULL is not anything...it is unknown. NULL does not equal anything. That is why you have to use the magic phrase IS NULL instead of = NULL in your SQL queries
You can refer this: http://weblogs.sqlteam.com/markc/archive/2009/06/08/60929.aspx
Been a while since I been coding in T-SQL, but I have an IF statement not working in a function. It must be a logic issue on my end but I can't see it.
If a piece of data, #pTownship is not blank and null than I am testing it to see if it is one, two, or three characters in length and returning the township number to the calling stored procedure. Following is my function code.
The issue is that when a piece of data, say 05N, is passed as #pTownship, the outer IF is not true the else is being executed so my internal IF conditions are never being executed. Since #pTownship is 05N it's NOT '' or NULL so why isn't my true condition being executed?
Thanks in advance for a second set of eyes.
CREATE FUNCTION core.fnTownshipNumber (#pTownship VARCHAR(50))
RETURNS INT
AS
BEGIN
DECLARE #TownshipNumber INT,
#InputLength INT;
IF #pTownship <> '' AND #pTownship <> NULL
BEGIN
SET #InputLength = LEN(#pTownship);
-- single character, based on the data, single character is always number so return it
IF #InputLength = 1
SET #TownshipNumber = CONVERT(INT, #pTownship);
-- double character, based on the data, double char are always number so return it
IF #InputLength = 2
SET #TownshipNumber = CONVERT(INT, #pTownship);
-- triple character, based on the data, third char is always direction so return first two
IF #InputLength = 3
SET #TownshipNumber = CONVERT(INT, SUBSTRING(#pTownship, 1, 2));
END;
ELSE
BEGIN
SET #TownshipNumber = NULL;
END;
RETURN #TownshipNumber;
END
The <> operator is not meant to compare to NULL. When you need to check for NULL, use
#pTownship IS NOT NULL
or if you prefer,
NOT (#pTownship IS NULL)
Related: Not equal <> != operator on NULL
In your case, you are comparing against both the empty string and null, a more concise way to capture both cases would be this:
IF NULLIF(#pTownship, '') IS NOT NULL BEGIN
/* ... */
END
You could omit the outer IF entirely, if you used this alternative:
SET #InputLength = LEN(COALESCE(#pTownship, ''));
The COALESCE function returns its second argument (the empty string in the example) when the first argument is NULL.
I think you might need to use the following form:
IF (#pTownship IS NOT NULL) AND (LEN(#pTownship) > 0)
I am not as certain about the second term; variations might also work. Parentheses could perhaps be omitted, but I might prefer to keep them.
On this, see How do check if a parameter is empty or null in Sql Server stored procedure in IF statement?
The following shows another way of implementing the logic with a case expression (not statement).
The first case implements the logic in a clear manner, though the initial when clause isn't really needed due to the else as a catch-all clause. The second variation takes advantage of Left() (or Substring()) tolerating a length greater than the input: it simply returns the entire string without error.
-- Sample data.
declare #Townships as Table ( Township VarChar(16) );
insert into #Townships ( Township ) values
( NULL ), ( '1' ), ( '23' ), ( '45N' ), ( 'Upper Lemming' );
-- Demonstrate conversion.
select Township,
case
when Township is NULL or Township = '' then NULL -- This can be left to the else clause.
when Len( Township ) in ( 1, 2 ) then Cast( Township as Int )
when Len( Township ) = 3 then Cast( Left( Township, 2 ) as Int )
else NULL end as TownshipNumber,
case
-- Since Left() doesn't mind being asked for more characters than are available ...
when Len( Township ) between 1 and 3 then Cast( Left( Township, 2 ) as Int )
else NULL end as TownshipNumberX
from #Townships;
When i run this query i expect the result will be 'false'
IF isnull(0,'') = ''
select 'true'
else
select 'false'
But sql Server tells me 'true', why?
In this case ISNULL(0,'') returns an integer. SQL Server will cast the second argument to an integer too, ie 0. So 0=0, hence the result is TRUE. Comparing directly to 0 would also return true:
IF 0 = ''
select 'true'
else
select 'false'
Using ISNULL and NULL like this is unusual. An ISNULL(someColumn='') function in a WHERE clause would prevent the optimizer from using any indexes that covered someColumn thus forcing a scan instead of an index seek.
Using IF statements in SELECT is impossible. Even in CASE statements, it's better to explicitly check for NULL than apply such transformations.
For your case, when compare two values, the '' will be converted to int first. The following:
SELECT CONVERT(INT, '')
returns 0, so 0=0 is true
If you want treat 0 as NULL, you can use NULLIF:
DECLARE #i INT = 0
IF NULLIF(ISNULL(#i, ''), 0) = ''
SELECT 'true'
ELSE
SELECT 'false'
This would return 'false'
ISNULL are identical when there are just two values (i.e. NULL and 0) so, it will be true in IF condition and select 'true' will be printed.
I recently ran into this pickle with the CASE-THEN-ELSE statement in SQL Server (2014 if it matters), to be more accurate, "the Simple" vs "the Searched" CASE expression. Until now, I thought that the only difference between these 2 is simply the format and/or the habit in writing both ways of the case expression but I guess I was completely wrong :)
MSDN Link
The CASE expression has two formats:
The simple CASE expression
compares an expression to a set of simple expressions to determine the
result.
The searched CASE expression evaluates a set of Boolean
expressions to determine the result.
Here is the example:
set nocount on
declare #test nvarchar(50) = null
select
#test as [The NULL Value],
case
when #test is null
then null
else 'Not Null???'
end as [As Expected],
case #test
when null
then null
else 'Not Null???'
end as [The Pickle]
And the result is:
The NULL Value As Expected The Pickle
-------------------------------------------------- ----------- -----------
NULL NULL Not Null???
Could someone provide a link to a MSDN documentation where this is explained, perhaps in a more detailed manner? :)
P.S.: I bet a lot of you folks were certain that both results would yield the same output :D
It's not weird at all ...
The "shortcut" way of
case #test
when null
then null
else 'Not Null???'
end as [The Pickle]
evaluates the variable/column (here: #test) against the values in the WHEN clauses (when null) with the regular equality operator - and comparing NULL using the standard equality operator (#test = null) is always undefined/NULL itself (standard SQL behavior), so it's not true
Therefore you are getting this result - Not Null??? - for your column The Pickle
If you want to check for NULL, you must use IS NULL like in your first example...
declare #t int =1
--simple case
select
case #t
when 1 then 1 else null end
The above query is expanded to below form..
select
case when #t=1 then 1 else null end
so a query with null will expand to below
declare #t int=null
select case #t
when null then null else 'notnull' end
is expanded to
select case when #t=null then null else 'notnull' end
which obviously evaluates to not null..
So in summary only in null case you will not get results you are expecting,try below to see
declare #t int=null
declare #t1 int =1
select
case when #t is null then null else 'notnull' end as 'Searchedcase',
case #t when null then null else 'notnull' end as'simple case',
case when #t1 =1 then 1 else null end as 'Searchedcase for value',
case #t1 when 1 then 1 else null end as'simple case for value'
See discussion of NULL and UNKNOWN from Transact-SQL reference to get a handle on why '=' doesn't work for NULL.
Simple CASE must be implicitly using '=', rather than IS NULL. So to make IS NULL explicit, use a Searched CASE expression.
Maybe Microsoft will add some functionality to the simple CASE expression to if NULL is encountered, then operator 'IS' is used?
I have a table that has a column of values that can be rowTypeID = (1,2,3, or null) . I would like to write a query that returns any row that doesn't have a value of 3 in it. In this example I want all NULL rows along with all 1,2 rows I just don't want rows with the value of 3
Set ANSI null ON is currently set for the database.
I'm curious as to why I can't write
select * from myTable where myCol <> 3
This query will not return any rows that have NULL in the myCol column
I have to write
select * from my Table where myCol <> 3 or myCol Is NULL
Do I always have to include the IS NULL or can I set it up so a where clause myCol <>3 will return rows that have Null as value for my Col
I think your approach is fine:
SELECT *
FROM MyTable
WHERE myCol <> 3 OR myCol IS NULL
Since you are asking for alternatives, another way to do it is to make your column NOT NULL and store another (otherwised unused) value in the database instead of NULL - for example -1. Then the expression myCol <> 3 will match your fake-NULL just as it would with any other value.
SELECT *
FROM MyTable
WHERE myCol <> 3
However in general I would recommend not to use this approach. The way you are already doing it is the right way.
Also it might be worth mentioning that several other databases support IS DISTINCT FROM which does exactly what you want:
SELECT *
FROM MyTable
WHERE myCol IS DISTINCT FROM 3
MySQL has the NULL-safe equal which can also be used for this purpose:
SELECT *
FROM MyTable
WHERE NOT myCol <=> 3
Unfortunately SQL Server doesn't yet support either of these syntaxes.
You must handle the NULLs one way or another, since expressions involving NULL evaluate to Unknown. If you want, you could instead do:
select *
from MyTable
where isnull(MyColumn, -1) <> 3
But this involves a magic number (-1), and is arguably less readable than the original test for IS NULL.
Edit: and, as SQLMenace points out, is not SARGable.
Whenever you test for a value all NULLs are omitted – after all, you are testing whether the value in some column passes certain criteria and NULL is not a value.
Do I always have to include the IS NULL or can I set it up so a where clause myCol <>3 will return rows that have Null as value for my Col?
You always, always, always have to include is null.
Because 3 does not equal Not/Applicable and it does not equal Unkown.
because you can't compare NULL to anything else, NULL is not even equal to NULL
DECLARE #i INT
DECLARE #i2 INT
SELECT #i = NULL, #i2 = NULL
IF #i = #i2
PRINT 'equal'
ELSE
PRINT 'not equal'