Why isn't 'WHERE NOT' with NULL-rows working? - mysql

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.

Related

MySql confusion between empty value (i.e. '') comparision against NULL [duplicate]

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

Selecting rows with null in integer columns using mysql query

I have a table named 'datatablecoulmn' with the following columns.
now i want all rows where the column FkID is NULL.FkID is an integer field
i tried the following queries
SELECT * FROM `datatablecoulmn` WHERE `FkID`=NULL
SELECT * FROM `datatablecoulmn` WHERE `FkID`<1
SELECT * FROM `datatablecoulmn` WHERE `FkID`='null'
All of these returns empty rows .Any help?
In MySQL, NULL is considered as a 'missing, unknown value', as opposed to no value. 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.
Use IS NULL condition in your query and try like this
SELECT * FROM `datatablecoulmn` WHERE `FkID` IS NULL
For handling NULL values MySQL provides three operators
IS NULL: operator returns true if column value is NULL.
IS NOT NULL: operator returns true if column value is not NULL.
<=>: operator compares values, which (unlike the = operator) is true
even for two NULL values.
You can refer to these links for more
Link 1,Link 2,Link 3
You can't compare with NULL. So you gotta check for YourColumn IS NULL (or maybe YourColumn IS NOT NULL.
NULL is a value like infinity is a number. In other words, not at all. NULL is the absence of certain information.
For the same reason that NaN (not a number) in IEEE754 floating point is not equal to other instances (or even the same instance) of NaN, nothing in SQL is equal to NULL, including NULL.
That's something that may sound strange but, when you think of the purpose of NULL, that of specifying unknown or inappropriate values, it makes sense.
In order to see if a value is NULL, you have to therefore use something like:
where COLUMN_NAME is null
More details on working with NULL in MySQL can be found here.
Use something like:
SELECT * FROM `datatablecoulmn` WHERE `FkID` is NULL
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 and not = or != or <> which is used by values.
Here is another way to exclude the records with FkID is NOT NULL:
SELECT D1.*
FROM datatablecoulmn D1
WHERE NOT EXISTS (SELECT D2.*
FROM datatablecoulmn D2
WHERE D2.`FkID` IS NOT NULL)

Why MYSQL IN keyword not considering NULL values

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

MySQL comparison with null value

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')

MySQL: selecting rows where a column is null

I'm having a problem where when I try to select the rows that have a NULL for a certain column, it returns an empty set. However, when I look at the table in phpMyAdmin, it says null for most of the rows.
My query looks something like this:
SELECT pid FROM planets WHERE userid = NULL
Empty set every time.
A lot of places said to make sure it's not stored as "NULL" or "null" instead of an actual value, and one said to try looking for just a space (userid = ' ') but none of these have worked. There was a suggestion to not use MyISAM and use innoDB because MyISAM has trouble storing null. I switched the table to innoDB but now I feel like the problem may be that it still isn't actually null because of the way it might convert it. I'd like to do this without having to recreate the table as innoDB or anything else, but if I have to, I can certainly try that.
SQL NULL's special, and you have to do WHERE field IS NULL, as NULL cannot be equal to anything,
including itself (ie: NULL = NULL is always false).
See Rule 3 https://en.wikipedia.org/wiki/Codd%27s_12_rules
SELECT pid FROM planets WHERE userid IS NULL
As all are given answers I want to add little more. I had also faced the same issue.
Why did your query fail? You have,
SELECT pid FROM planets WHERE userid = NULL;
This will not give you the expected result, because from mysql doc
In SQL, the NULL value is never true in comparison to any other value, even NULL. An expression that contains NULL always produces a NULL value unless otherwise indicated in the documentation for the operators and functions involved in the expression.
Emphasis mine.
To search for column values that are NULL, you cannot use an expr = NULL test. The following statement returns no rows, because expr = NULL is never true for any expression
Solution
SELECT pid FROM planets WHERE userid IS NULL;
To test for NULL, use the IS NULL and IS NOT NULL operators.
operator IS NULL tests whether a value is NULL.
operator IS NOT NULL tests whether a value is not NULL.
MySQL comparison operators
There's also a <=> operator:
SELECT pid FROM planets WHERE userid <=> NULL
Would work. The nice thing is that <=> can also be used with non-NULL values:
SELECT NULL <=> NULL yields 1.
SELECT 42 <=> 42 yields 1 as well.
See here: https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#operator_equal-to
Info from http://w3schools.com/sql/sql_null_values.asp:
1) NULL values represent missing unknown data.
2) By default, a table column can hold NULL values.
3) NULL values are treated differently from other values
4) It is not possible to compare NULL and 0; they are not equivalent.
5) It is not possible to test for NULL values with comparison
operators, such as =, <, or <>.
6) We will have to use the IS NULL and IS NOT NULL operators instead
So in case of your problem:
SELECT pid FROM planets WHERE userid IS NULL
Had the same issue where query:
SELECT * FROM 'column' WHERE 'column' IS NULL;
returned no values.
Seems to be an issue with MyISAM and the same query on the data in InnoDB returned expected results.
Went with:
SELECT * FROM 'column' WHERE 'column' = ' ';
Returned all expected results.
SELECT pid FROM planets WHERE userid is null;
I had the same issue when converting databases from Access to MySQL (using vb.net to communicate with the database).
I needed to assess if a field (field type varchar(1)) was null.
This statement worked for my scenario:
SELECT * FROM [table name] WHERE [field name] = ''