371

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)
Ben
  • 51,770
  • 36
  • 127
  • 149
Maxim Gershkovich
  • 45,951
  • 44
  • 147
  • 243

10 Answers10

408

<> 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.

Uddhav P. Gautam
  • 7,362
  • 3
  • 47
  • 64
OMG Ponies
  • 325,700
  • 82
  • 523
  • 502
  • 4
    Actually, I believe it is `<>` that is in the 92 spec but most vendors support `!=` and/or it is included in a later spec like 99 or 03. – Thomas Apr 14 '11 at 04:44
  • 2
    @Thomas: Oracle didn't support `!=` until ~9i as I understand, which brought in a lot of ANSI-92 syntax. My belief is MySQL is similar, starting support in 4.x. – OMG Ponies Apr 14 '11 at 04:46
  • That would seem to suggest that `!=` might have been included in a later spec as an alternate to `<>`. Don't have my hands on new specs so I can't say for sure. – Thomas Apr 14 '11 at 16:14
  • @Thomas: To my knowledge, Oracle supported `<>` only prior to 9i. – OMG Ponies Apr 15 '11 at 00:24
  • I don't doubt that. I do have the SQL 92 spec and between the two, only `<>` is referenced. I doubt support of the `<>` token was specifically was required for any of the levels so it is likely that the vendors did what they wanted for a time. TBH, it would be more surprising to hear that someone like DB2 didn't support `<>` until recently than Oracle. – Thomas Apr 15 '11 at 00:53
  • 4
    Is the result of `WHERE MyColumn != NULL` or `WHERE MyColumn = NULL` deterministic? Or in other words, is it guaranteed to always return 0 rows, no matter if `MyColumn` is nullable in the database or not? – Slauma Dec 07 '11 at 15:20
  • Oracle has supported `!=` since at least 7.13, and I believe even before that. But I did find the following statement in the Oracle 8 docs: ***"Some forms of the inequality operator may be unavailable on some platforms."*** http://docs.oracle.com/cd/A64702_01/doc/server.805/a58225/ch3all.htm#997665 – dbenham Jul 03 '12 at 16:58
  • 36
    It should also be noted that because `!=` only evaluates for values, doing something like `WHERE MyColumn != 'somevalue'` will not return the NULL records. – jsumrall Feb 12 '15 at 15:38
  • Would it hurt anyone to add an alias? Is there a use case for actual `<> NULL`? – leitasat Sep 15 '20 at 13:19
122

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.

Barry Brown
  • 20,233
  • 15
  • 69
  • 105
  • 3
    +1. And, contrary to the OP statement this is not "Microsoft SQL". Trinary logic is defined in the SQL Standard and MS in this point adheres to the standard. – TomTom Apr 14 '11 at 04:23
  • 6
    I wasn't suggesting that this is a Microsoft only behavior. I was simply stating that I observed it on Microsoft SQL Server. – Maxim Gershkovich Apr 14 '11 at 04:27
  • 21
    Out of interest, are there any situations where this (expected) behaviour is useful? It just seems to me having `'a' != null` NOT returning a value (`true`/`1`) is counter intuitive and catches me out from time to time! I'd have thought "some value compared to no value" would always be "not equal", but maybe that's just me?!? – DarthPablo Jun 23 '14 at 14:56
  • 2
    I think it's interesting that people describe NULL as '_having no value_' . Similar, then, to saying the number 1 'has a value' when it actually is a value. But NULL represents non-value.. – systemaddict Jun 27 '17 at 20:19
  • 1
    As a manual workaround, you could commonly `SELECT * FROM MyTable WHERE coalesce(MyColumn, 'x') <> 'x'` to assign a constant if it is NULL value, providing you give an appropriate datatype for the sentinel value x (in this case a string/char). This is TSQL syntax but Oracle and other engines have similar features. – systemaddict Jun 27 '17 at 20:25
  • Here is a fun quiz to check if you understood how it works: https://blog.drnielsen.de/php/laravel/how-null-works – Adam Dec 31 '20 at 12:51
28

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...

Cade Roux
  • 88,164
  • 40
  • 182
  • 265
  • 8
    +1 ... not soon enough. Now when can I get "duplicate" NULLs in an index? :( –  Apr 14 '11 at 05:19
  • You can get duplicate NULLs in a SQL Server index by adding a WHERE clause in a filtered index (e.g. `create unique index UK_MyTable on MyTable (Column) where Column is not null`): http://msdn.microsoft.com/en-us/library/cc280372.aspx – Anthony Mills May 10 '14 at 23:14
  • 4
    Note from the docs: _When `SET ANSI_NULLS` is OFF, the Equals (=) and Not Equal To (<>) comparison operators do not follow the ISO standard. A SELECT statement that uses `WHERE column_name = NULL` returns the rows that have null values in column_name. A SELECT statement that uses `WHERE column_name <> NULL` returns the rows that have nonnull values in the column. Also, a SELECT statement that uses `WHERE column_name <> XYZ_value` returns all rows that are not XYZ_value and that are not NULL._ IMHO, this last statement seems a little odd in it's exclusion of nulls from the results! – DarthPablo Jun 23 '14 at 15:06
  • 5
    **Important** note from the [msdn doc](http://msdn.microsoft.com/en-us/library/ms188048.aspx): *In a future version of SQL Server [newer than 2014], ANSI_NULLS will always be ON and any applications that explicitly set the option to OFF will generate an error. **Avoid using this feature** in new development work, and plan to modify applications that currently use this feature.* – Otiel Jan 15 '15 at 08:43
12

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.

Jeff Mergler
  • 1,384
  • 20
  • 27
  • This is the best workaround, just be careful in the few cases where an empty string vs. null comparison is not meaningless. – sisisisi Oct 20 '20 at 14:46
11

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.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Mahendra Liya
  • 12,912
  • 14
  • 88
  • 114
  • 2
    "In SQL, anything you evaluate / compute with NULL results into 'NULL'" -- incorrect. The result you mean is UNKNOWN. – onedaywhen Apr 14 '11 at 07:39
  • 1
    @MahendraLiya the isNull function is not provided to check for NULLS, but it "[Replaces NULL with the specified replacement value.](https://learn.microsoft.com/en-us/sql/t-sql/functions/isnull-transact-sql)". You should use IS NULL or IS NOT NULL instead of ISNULL which is a different thing. – Reversed Engineer May 31 '18 at 15:07
8

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)

beat
  • 1,857
  • 1
  • 22
  • 36
dkretz
  • 37,399
  • 13
  • 80
  • 138
6

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.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Manngo
  • 14,066
  • 10
  • 88
  • 110
  • This is the same "nonsensical" "logic" that @Hove is describing in his answer. The truth is that in this context there is no need for that extra paraphernalia; it could be easily assumed that when we are comparing something to a `NULL` we mean that we are comparing a value to 'having a `NULL` value', not the value to "the undetermined value that the underlaying `NULL` is ¿having? but that we don't know", which obviously we are not going to be able to ever know. That would really ease things up. – Pere Apr 12 '18 at 08:57
  • 1
    @Pere I wouldn’t say that it is strictly “nonsensical”, and I’m not sure that writing `IS NULL` is much more arduous than writing `= NULL`. I think it would be more consistent if `WHERE columnA = columnB` has the same interpretation as `WHERE columnA = NULL`, rather than treat the latter as a special case. Remember that `NULL` is _not_ a value. In programming languages where it _is_ legitimate to test `variable == null` it is because `null` has a different meaning; it doesn’t represent something unknown, but a deliberate resetting of a value. Not so with SQL. – Manngo Apr 12 '18 at 09:06
  • That's why I put it between quotes, @Mangoo ;) (and also "logic"). Don't get mad at me; I was talking about the ANSI "reasoning", not about your explanation. I agree in that there is no overhead between `IS NULL` AND `=NULL` in your latest example. But take a look at Hover's last one. I'm tired of experiencing it again and again, having to do loads of ¿unnecessary? extra checking... – Pere Apr 12 '18 at 14:34
6

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.

Vincent Ramdhanie
  • 102,349
  • 23
  • 137
  • 192
  • 6
    I've always enjoyed confused people when I sometimes use `null = null` where one might use `1=0` in some ad-hoc query. And if they complain, I change it to `null != null` :) – SWeko Apr 14 '11 at 07:30
  • 11
    "NULL = NULL is false" That's not so. NULL = NULL evaluates to **unknown** and not false. – nvogel Apr 14 '11 at 08:22
  • @dportas that is so but I meant that in a conditional it will not be evaluated as true. – Vincent Ramdhanie Apr 14 '11 at 11:17
  • @VincentRamdhanie neither as false; in fact, in postgres it will be evaluated as NULL – Pere Apr 12 '18 at 08:46
2

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

0

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

Shadow
  • 13
  • 3