I must to check if two values, X and Y are different. If both are null, they must be considered as equal.
The unique way I found is:
select 1 as valueExists
where (#X is null and #Y is not null)
or (#Y is null and #X is not null)
or (#X <> #Y)
Is there a smart way to write this expression?
Thanks!
I think you could use COALESCE for that
WHERE coalesce(#X, '') <> coalesce(#Y, '')
What it does it returns an empty string if one of variables is null, so if two variables are null the two empty strings become equal.
I typically use a technique I picked up from here
SELECT 1 AS valuesDifferent
WHERE EXISTS (SELECT #X
EXCEPT
SELECT #Y)
WHERE EXISTS returns true if the sub query it contains returns a row. This will happen in this case if the two values are distinct. null is treated as a distinct value for the purposes of this operation.
You could try using NULLIF like this:
WHERE NULLIF(#X,#Y) IS NOT NULL OR NULLIF(#Y,#X) IS NOT NULL
You can use ISNULL
WHERE ISNULL(#X,'') <> ISNULL(#Y,'')
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
I inherited some old stored procedures today, and came across several examples that followed this general pattern, where #Test is some INT value:
IF #Test IS NOT NULL AND #Test > 0
-- do something...
My understanding is that if #Test is NULL, then it has no value, and is not greater than, less than or even equal to zero. Therefore, testing for NULL is redundant in the above code:
IF #Test > 0
-- do something...
This second version seems to work just fine, and is far more readable IHMO.
So, my question: Is my understanding of NULL being unnecessary in this instance correct, or is there some obvious use-case I'm overlooking here where it could all go horribly wrong?
Note: In some cases, it was obvious that the intent was checking for the existence of a value, and I've changed those to IF EXISTS... my question is more concerned with the general case outlined above.
In SQL all comparisons to a NULL value evaluate to false.
So you always have to check explicitly for NULL, if you wish to act on it.
So, in this case, the additional test is not necessary.
#FlorianHeer is right on. NULL > 0 will eventually evaluate to false but as #Pred points out that is because Null > 0 actually evaluates to null and null cast to a bit is false....
A null is an unknown and therefore any comparison with it is also unknown. Think of arithmetic functions such as addition 1 + NULL = NULL, or concatenation 'A' + NULLL = NULL. NULL means the SQL database engine cannot interpret what its value is so any function or comparison on it is also unknown.
#MikkaRin pointed out that it is the assumption in the ELSE portion of a case statement or IF statement where that can become problematic but lets also think about this in the context of a join and how you may or may not want to see the results.
DECLARE #Table1 AS TABLE (Col INT)
DECLARE #Table2 AS TABLE (Col INT)
INSERT INTO #Table1 VALUES (1),(2),(3)
INSERT INTO #Table2 VALUES (1),(NULL),(3),(4)
SELECT *
FROM
#Table1 t1
INNER JOIN #Table2 t2
ON t1.Col <> t2.Col
Naturally you might think because NULL would be not equal to 1,2,3 that it should be included in the result set. But null is unknown so SQL is saying well I don't know if NULL could be 1,2,3 so I cannot return that as a result.
Now lets do the same thing but add a NULL in the first table:
DECLARE #Table1 AS TABLE (Col INT)
DECLARE #Table2 AS TABLE (Col INT)
INSERT INTO #Table1 VALUES (1),(2),(3),(NULL)
INSERT INTO #Table2 VALUES (1),(NULL),(3),(4)
SELECT *
FROM
#Table1 t1
INNER JOIN #Table2 t2
ON t1.Col = t2.Col
Again you might think that NULL is = to NULL but any comparison of NULL is considered unknown so even though both tables have NULL in it it will not be returned in the dataset.
Now consider:
DECLARE #Table1 AS TABLE (Col INT)
INSERT INTO #Table1 VALUES (1),(2),(3),(NULL)
SELECT *, CASE WHEN Col < 2 THEN Col ELSE 1000 END as ColCase
FROM
#Table1 t1
Which will make even the NULL 1000 the question is should NULL an unknown be 1000? if NULL is unknown how do we know that it isn't less than 2?
For a lot of your operations it may simply be enough to compare #Value > 1 but especially when you start dealing with ELSE in case of IF statements or joining on the antithesis you should consider dealing with the NULLs. Such as using ISNULL() or COALESCE() as #GuidoG points out.
IMHO being explicit about your intentions during operations to appropriately account for null values out weighs the minimal savings of typing.
Compare with NULL is necessary if you use ELSE statements:
for example:
declare #t int
set #t=null
if (#t>0) print '1' -- works fine
if (#t<0) print '2' --works fine
if (#t>0)
print '3' --works fine
else print '4' --here we start getting problems, because we are sure that #t<=0 that is obviously not true
you could replace it with
if isnull(#test, 0) > 0
This way it will be shorter and you still have checked everything
another interesting example:
SELECT (null > 0) AS a, !(null > 0) AS b
value of both a and b will be NULL
From my understanding, in some cases null checks are added sometimes to short circuit OR logic. For example, consider the following:
select * from tbl where (#id is null or #id > id)
If you pass in a value for #id, it tests the first condition (#id is null) and sees that it's false, but since it's part of an OR statement, it then goes ahead and then runs the #id > id comparison to see what that one returns as well. OR statements only need one true returned for the whole thing to resolve to true, and must keep testing until it comes across an OR condition that does.
Whereas if you pass in null for the #id parameter, as soon as it gets to the first condition and it returns true. Seeing that the next it's part of an OR statement, SQL knows it doesn't even have to do any of the following comparison, because the entire OR statement has already resolved to true. The #id > id comparison and will not even run it. This can save a ton of processing if it's a huge table or complex join, etc.
Issue
I want to write a query that will select all from a table where my string value is equal to two columns concatenated together.
This is plain English version:
#MYSTRING varchar(50)
SELECT ALL FROM [FFLOCNP] WHERE COLUMN1 + COLUMN2 = #MYSTRING
I have tried to use the COALESCE but i have never used this before and it is returning me an error:
#CODE varchar(50)
SELECT * FROM [dbo].[FFLOCNP] WHERE COALESCE([LOCTRY], '') || COALESCE([LOCLCN], '') = #CODE
you have to use ISNULL for this.
Use below query may be it helps you.
SELECT * FROM [FFLOCNP] WHERE ISNULL(COLUMN1,'') + ISNULL(COLUMN2,'') = #MYSTRING
Be careful, when using ISNULL instead of COALESCE. ISNULL limits the returned value to the datatype of the first input parameter. In the given example column V1 will be implicitly defined with nvarchar(1), because the longest text in column V1 consists of only one character. ISNULL(V1, [param2]) will therefor return always a one character long string, regardless of the length of the second parameter. In your case ISNULL would work, if you wanted to replace a NULL with an empty string. If you wanted to replace a NULL with a longer string then you MUST use COALESCE instead of ISNULL. COALESCE returns the full string in parameter 2 regardless of the datatype of parameter 1. Apart from this COALESCE is standard SQL whereas ISNULL is a flavor of SQL-Server. Standard SQL should be preferred to T-SQL flavor to get more portable code.
WITH CTE_SRC AS
(
SELECT
[V1]
,[V2]
FROM
(VALUES
(N'A', N'BB')
,(NULL, N'BB')
,(N'A', NULL)
) T([V1],[V2])
)
SELECT
ISNULL([V1], '1234') AS [ISNULL]
,COALESCE([V1], '123') AS [COALESCE]
FROM
CTE_SRC
Result
ISNULL COALESCE
------ --------
A A
1 123
A A
What is the right practice of checking NULLs in SQL Case ?
1) Using ISNULL()
WHEN (ISNULL(TABLE.COLUMN,0) > 0) THEN ....
2) Using IS NULL
WHEN TABLE.COLUMN IS NOT NULL THEN ....
If you are checking any condition then always use 'is null' and if replacing any value with a different one, then use isnull(a,b).
Check the following -
http://msdn.microsoft.com/en-us/library/ms184325.aspx
Read the last line specially!!!
Second one is right if you want to check for null value in SQL case..
Both are correct if the values in the column are either greater than 0 or null.
You can refer to this post if you want to know about the weird behavior of nulls in SQL Server.
This is also another approach to check for NON NULL values.
Checking for length of the column if it is greater than 1 or equal 1 then its a NON NULL
value.
declare #emp table
(
fname varchar(50)
);
INSERT into #emp VALUES('vishwanath');
INSERT into #emp VALUES('chetan');
INSERT into #emp VALUES(NULL);
INSERT into #emp VALUES(NULL);
SELECT * FROM #emp
where len(fname)>=1 and fname<>'';
Gives..
fname
--------------------------------------------------
vishwanath
chetan
when you are checking whether a column is null or not it is better to use
col IS NULL
when you use ISNULL(TABLE.COLUMN,0) > 0) function , null values have to be converted to zero fist then should take all values greater than zero
this function is useful in another occasion. lets say if I want to return all the null values as well as the negative values.
so the query would be
select * from table where col is null or col<0
this can be re-written as
select * from table isnull(col,-1)<0
Both are correct in there cause, however ISNULL can be helpfull when you want to use a constant value instead of NULL in that column while calculating SUM, average, etc.
For example you can check :http://www.w3schools.com/sql/sql_isnull.asp
Due to this feature I personally use ISNULL/COALESCE for calculation purposes.
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'