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
Related
Maybe I'm just missing something. Since the problem is too unspecific to google it / search for it, I am now looking for help here. Tested in MySQL
My Question: Why doesn't this SELECT output [ id=2 ]?
SELECT `id` FROM `testtable1` WHERE NOT (`key_boolean` = 1);
Table Definition and Test-Data:
CREATE TABLE IF NOT EXISTS `testtable1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key_boolean` tinyint NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) AUTO_INCREMENT=1;
INSERT INTO `testtable1` (`key_boolean`) VALUES (1);
INSERT INTO `testtable1` () VALUES ();
In the table is now stored:
id
key_boolean
1
1
2
NULL
Edit:
Based on the answers I actually found some more similar questions on StackOverflow. This post fits well for MySQL: MYSQL syntax not evaluating not equal to in presence of NULL
The expression key_boolean = 1 evaluates to NULL when key_boolean is NULL. So you intermediately have NOT NULL for NOT (key_boolean = 1). NOT NULL, in turn, also evaluates to NULL. And as NULL isn't true (yet not false either -- in SQL a ternary logic applies), the row is not selected.
With the exception of a few, all comparison operations, like =, evaluate to NULL, if one of their operands is NULL. One notable exception in MySQL, in this case, is the NULL-safe equal <=>, which behaves like you might want it.
You can select the (sub) expressions from your test table and see their results for yourself.
SELECT *,
key_boolean = 1,
NOT (key_boolean = 1),
key_boolean <=> 1,
NOT (key_boolean <=> 1)
FROM testtable1;
db<>fiddle
Personally, I find the answers from #sticky-bit and #ysth very helpful, but I would like to share some more information about my research:
Conclusion:
SQL follows the three-value logic (3VL). That means besides TRUE(1) and FALSE(0) there is also NULL. And that means that if one of the operands in a comparison is NULL, the result is also NULL. See also truth table on Wikipedia: https://en.wikipedia.org/wiki/Null_(SQL)#Comparisons_with_NULL_and_the_three-valued_logic_(3VL)
Example 1 without NOT:
SELECT id FROM testtable1 WHERE (key_boolean = 1);, so:
[row 1] key_boolean = 1 --> 1 = 1 --> TRUE
[row 2] key_boolean = 1 --> NULL = 1 --> NULL
-> so, row 1 is selected.
Example 2, just like example 1, only negated, so with NOT:
SELECT id FROM testtable1 WHERE NOT (key_boolean = 1);, so
[row 1] NOT (key_boolean) = 1 --> 1 = 1 --> TRUE
[row 2] NOT (key_boolean) = 1 --> NULL = 1 --> NULL
-> empty result.
Solutions to the problem:
As #sticky-bit has already written, there is NULL-safe equal in MySQL, which in this example also achieves the desired result.
<=> unfortunately only works in MySQL (and then also in MariaDB). I found a comparison of the different dialects at https://modern-sql.com/feature/is-distinct-from. #ysth's suggestion with "CASE WHEN" probably works in all dialects, but blows up select-terms.
In my specific case (no longer part of the actual question) I have now solved it with a COALESCE() - determined a default for NULL values, because in my case, i have to not only support mysql, see:
SELECT `id` FROM `testtable1` WHERE NOT (COALESCE(`key_boolean`, 0) = 1);
Further reading:
If, like me, one has never heard of NULL-safe equal operator <=>, see: What is this operator <=> in MySQL?
Now I am by no means a database technician, but know NULL as undefined (from other programming languages). The obvious question to me is why at least SQL doesn't use the NULL-safe equal every time. See: Is there a reason not to use <=> (null safe equals operator) in mysql instead of =? and Is there a reason not to use <=> (null safe equals operator) in mysql instead of =? [each with a marked post].
NULL conceptually means indeterminate. So NOT NULL is also NULL, and false. You can test CASE WHEN key_boolean=1 THEN 0 ELSE 1 END if you want to include NULL.
Hope the question is not too generic. Couldn't find anything on the site or in SQL documentation:
While coding, i tested this, and to my surprise it worked:
SELECT * FROM cal_entry WHERE cal_entry.parent_id <> 'null'
It actually shows the rows without the ones with NULL values (these are real NULL values in database, not strings with 'null' inside).
According to the docs, I should have used NOT NULL, of course. By the way, it doesn't work with = 'null', like it is correctly stated in the docs.
Can someone explain that?
You are selecting all rows where <> 'null' is true.
Comparing(equals or not-equals) to null is null, so if a row where cal_entry.parent_id is null, your condition will be false/null.
So your query gets all rows that are not null, nor contain the string 'null'.
(Note, you could just as well have written <>'something_else')
Assuming parent_id in an int column the query will return all non-null, non-zero rows:
SELECT *
FROM (
SELECT NULL AS parent_id UNION ALL
SELECT 0 UNION ALL
SELECT 1 UNION ALL
SELECT 2
) AS cal_entry
WHERE cal_entry.parent_id <> 'null'
-- returns 1 and 2 but not 0!
When comparing a number to string MySQL will convert the string to number. Some examples:
'null' becomes 0
'asdf' becomes 0
'1asdf' becomes 123
'1' becomes 1
Your query will behave like:
WHERE cal_entry.parent_id <> 0
this operator give you result of not equal to. ex. $var != null.
we write in mysql as <>. this is kind of validation that the value shoud never be equal to null.
When working with null following two statements should always be taken note of -
An expression can be null, but it can never be equal to null.
Two nulls are never equal to each other.
So, in your query wherever there is a comparison null<>null it returns true by second statement.
Also, always account the possibility that some rows might contain null -
Select * from cal_entry where cal_entry.parent_id!=10
This query would leave out the rows with null entries. Instead use -
Select * from cal_entry where cal_entry.parent_id!=10 or cal_entry.parent_id is null
I'm having a problem with some SQL queries that I cant figure out.
SELECT * FROM MasterList WHERE Requested <> "Yes";
If I run the above query on my table I get 60 records returned. However There should be close to 300. I think the issue is, some of the records are just blank in the Requested field and others are NULL. But I would have thought NULL would still count as not equal to "Yes" wouldnt it? If not, is there a way around that without having to go back and 'blank' all the null fields?
Nulls are not counted in comparison, if you want null values to be returned then you need to execute the following query:
SELECT * FROM MasterList WHERE Requested <> "Yes" OR Requested IS NULL;
<=>
NULL-safe equal. This operator performs an equality comparison like the = operator, but returns 1 rather than NULL if both operands are NULL, and 0 rather than NULL if one operand is NULL.
mysql> SELECT 1 <=> 1, NULL <=> NULL, 1 <=> NULL;
-> 1, 1, 0
mysql> SELECT 1 = 1, NULL = NULL, 1 = NULL;
-> 1, NULL, NULL
in your case use:
SELECT * FROM MasterList WHERE not Requested <=> "Yes"
It happens because null <> 'Yes' expression evaluates to null, thus you should add a separate is null check to include records that meet this condition in your result set:
select * from MasterList where Requested <> "Yes" or Requested is null
P.S.: comparison of null with anything, even with null itself, always returns null.
I've struggled with the same issue and someone introduced me to the IS DISTINCT FROM construct. Very useful but not available for all DBMS!
SELECT * FROM MasterList WHERE Requested IS DISTINCT FROM "Yes";
I am using the following query:
select count(*) from Table1 where CurrentDateTime>'2012-05-28 15:34:02.403504' and Error not in ('Timeout','Connection Error');
Surprisingly, this statement doesnot include the rows having Error value as NULL.My intention is to filter only rows with Error value as 'Timeout' (or) 'Connection Error'. I need to give an additional condition( OR Error is NULL) to retrieve the correct result.
Why is MYSQL filtering out results with NULL values?
I thought that IN keyword would return a boolean result (1/0) and now i understand that some MYSQL keywords doesnt return boolean values,it might return NULL too....but Why is it treating NULL as special?
This :
Error not in ('Timeout','Connection Error');
is semantically equivalent to:
Error <> 'TimeOut' AND Error <> 'Connection Error'
Rules about null comparison applies to IN too. So if the value of Error is NULL, the database can't make the expression true.
To fix, you could do this:
COALESCE(Error,'') not in ('Timeout','Connection Error');
Or better yet:
Error IS NULL OR Error not in ('Timeout','Connection Error');
Or more better yet:
CASE WHEN Error IS NULL THEN 1
ELSE Error not in ('Timeout','Connection Error') THEN 1
END = 1
OR doesn't short-circuit, CASE can somehow short-circuit your query
Perhaps a concrete example could illustrate why NULL NOT IN expression returns nothing:
Given this data: http://www.sqlfiddle.com/#!2/0d5da/11
create table tbl
(
msg varchar(100) null,
description varchar(100) not null
);
insert into tbl values
('hi', 'greet'),
(null, 'nothing');
And you do this expression:
select 'hulk' as x, msg, description
from tbl where msg not in ('bruce','banner');
That will output 'hi' only.
The NOT IN is translated as:
select 'hulk' as x, msg, description
from tbl where msg <> 'bruce' and msg <> 'banner';
NULL <> 'bruce' can't be determined, not even true, not even false
NULL <> 'banner' can't be determined, not even true not even false
So the null value expression, effectively resolved to:
can't be determined AND can't bedetermined
In fact, if your RDBMS supports boolean on SELECT(e.g. MySQL, Postgresql), you can see why: http://www.sqlfiddle.com/#!2/d41d8/828
select null <> 'Bruce'
That returns null.
This returns null too:
select null <> 'Bruce' and null <> 'Banner'
Given you are using NOT IN, which is basically an AND expression.
NULL AND NULL
Results to NULL. So it's like you are doing a: http://www.sqlfiddle.com/#!2/0d5da/12
select * from tbl where null
Nothing will be returned
Because null is undefined so null does not equal null. You always have to explicitly handle null.
IN returns NULL if the expression on the left hand side is NULL. In order to get the NULL values, you have to do:
select count(*) from Table1 where CurrentDateTime>'2012-05-28 15:34:02.403504' and (Error not in ('Timeout','Connection Error') or Error is null);
IN returns a trivalent BOOLEAN (which accepts NULL as a value). NOT IN returns the trivalent negation of IN, and negation of NULL is a NULL.
Imagine we have a table with all numbers from 1 to 1,000,000 in id and this query:
SELECT *
FROM mytable
WHERE id IN (1, 2, NULL)
or its equivalent:
SELECT *
FROM mytable
WHERE id = ANY
(
SELECT 1
UNION ALL
SELECT 2
UNION ALL
SELECT NULL
)
The predicate returns TRUE for 1 and 2 and NULL for all other values, so 1 and 2 are returned.
In its oppposite:
SELECT *
FROM mytable
WHERE id NOT IN (1, 2, NULL)
, or
SELECT *
FROM mytable
WHERE id <> ALL
(
SELECT 1
UNION ALL
SELECT 2
UNION ALL
SELECT NULL
)
, the predicate returns FALSE for 1 and 2 and NULL for all other values, so nothing is returned.
Note that boolean negation not only changes the operator (= to <>), but the quantifier too (ANY to ALL).
#Michael Buen ' s answer was the right answer for my case, but let me simplify why.
#Michael says in his post:
Error not in ('Timeout','Connection Error');
is semantically equivalent to:
Error <> 'TimeOut' AND Error <> 'Connection Error'
Rules about null comparison applies to IN too. So if the value of Error is NULL, the database can't make the expression true.
And in [1] I found this sentence which confirms his most important statement for understanding why IN fails with NULL. In the specifications ("specs") in [1] you will: "If one or both arguments are NULL, the result of the comparison is NULL, except for the NULL-safe <=> equality comparison operator."
So yeah, the thing is that sadly Mysql gets lost in such a case. I think Mysql designers shouldn't have done this, because when I compare 2 to NULL, Mysql SHOULD be able to see they are DIFFERENT, and not simply throwing mistaken results. For example, I did:
select id from TABLE where id not in (COLUMN WITH NULLS);
then it throws EMPTY results. BUT. If I do
select id from TABLE where id not in (COLUMN WITH OUT NULLS);
it shows the right result. So when using the IN operator, you must filter out the NULLS. This is not a desired behavior for me as a user, but it's documented in the specifications in [1]. I think that languages and technology should be simpler, in the sense that you should be able to DEDUCE without the need of reading the specs. And truly, 2 is DIFFERENT from NULL, I should be the one in charge of controlling and taking care of mistakes of a higher level of abstraction, but MySQL SHOULD throw a FALSE result when comparing NULL with a specific value.
References for the specs: [1] http://dev.mysql.com/doc/refman/5.6/en/type-conversion.html
Sorry for posting twice in the same forum, but I want to illustrate another example:
I agree with #Wagner Bianchi in [2] in this forum when he says:
<< It’s very trick when dealing with data and subqueries>>
Moreover, this should NOT be the behavior, I think Mysql's designers are mistaken when they made this decision documented in [1]. The design should be different. Let me explain: You know that when comparing
select (2) not in (1, 4, 3);
you will get:
+----------------------+
| (2) not in (1, 4, 3) |
+----------------------+
| 1 |
+----------------------+
1 row in set (0.00 sec)
BUT if in the list you have at least one NULL then:
select (2) not in (1, NULL, 3);
throws:
+-------------------------+
| (2) not in (1, NULL, 3) |
+-------------------------+
| NULL |
+-------------------------+
1 row in set (0.00 sec)
This is pretty absurd.
We are not the first ones in getting confused by this. See [2]
References:
[1] http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_in
[2] http://blog.9minutesnooze.com/sql-not-in-subquery-null/comment-page-1/#comment-86954
I have a column called CODE in a MySQL table which can be NULL. Say I have some rows with CODE='C' which I want to ignore in my select result set. I can have either CODE=NULL or CODE!='C' in my result set.
The following query does not return a row with CODE as NULL:
SELECT * from TABLE where CODE!='C'
But this query works as expected and I know it is the right way to do it.
SELECT * from TABLE where CODE IS NULL OR CODE!='C'
My question is why does having only CODE!='C' does not return rows where CODE=NULL? Definitely 'C' is not NULL. We are comparing no value to a character here. Can someone throw some light as why it doesn't work that way?
In MySQL, NULL is considered as a 'missing, unknown value', as opposed to no value. Take a look at this MySQL Reference on NULL.
Any arithmetic comparison with NULL does not return true or false, but returns NULL instead., So, NULL != 'C' returns NULL, as opposed to returning true.
Any arithmetic comparison with 'NULL' will return false. To check this in SQL:
SELECT IF(NULL=123,'true','false')
To check NULL values we need to use IS NULL & IS NOT NULL operator.
Based on my tests and the documentation here: http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html
You can compare null and get a boolean result using <=>
NOTE: it looks like NOT EQ operator, but it's EQ operator
For example:
select x <=> y;
or
select #x <=> #y;
This also compares string vs null, string vs string, etc.
In SQL, the NULL value is a special value, not comparable with any other one.
The result of a direct comparison with a NULL is always NULL, although (unfortunately) you may find FALSE in some implementation.
To test a null value you should use IS NULL and IS NOT NULL.
SELECT *
FROM `table_name`
WHERE IFNULL(`column_name` != 'C', TRUE)
The specified problem can also appear in joins and the above answers aren't particularly helpful. The way I prefer to do it is by coalescing to otherwise impossible value. For example, this
select foo from bar
inner join baz on bar.x = baz.y
won't work if bar.x and baz.y are both nulls (join won't bring results). The workaround is to use e.g.
select foo from bar
inner join baz on coalesce(bar.x, -1) = coalesce(baz.y, -1)
where -1 is "impossible" value meaning it can never appear in the data set.
select * from user where application_id='1223333344' and name is null;
I use:
SELECT * from TABLE where NOT(CODE <=> 'C')