Xaprb

Stay curious!

Why IS NULL doesn’t always work in MySQL

with 7 comments

How can a query like “SELECT * FROM tbl WHERE col IS NULL” return a row where the column has a (non-NULL) value? Read on to find out.

First, a demonstration

Try this one yourself:

create table test(
   a int not null auto_increment,
   b int not null,
   primary key (a)
);

insert into test(a, b) values (0, 1);

select * from test where a is null;
+---+---+
| a | b |
+---+---+
| 1 | 1 | 
+---+---+

Your reaction might be, as mine was, “what the heck is going on here?” And then you might re-try the query, just because you can’t believe your eyes, and guess what you get this time?

select * from test where a is null;
Empty set (0.00 sec)

What happened?

A lot of weird things happened here:

  1. MySQL didn’t insert 0 into the first column; it inserted 1.
  2. I asked for rows where the first column is NULL, which should return no rows, but I got a row where it is clearly not NULL.
  3. I repeated the query and got a different result.

It’s a feature, not a bug

Believe it or not, these are features, not bugs. No, really!

  1. MySQL inserted a 1 into the column because by default, inserting either a zero or nothing (e.g. omitting the column or explicitly inserting NULL) into an auto-increment column tells MySQL to generate the next value in the auto-increment sequence. In newer MySQL versions, you can set the Server SQL Mode to disable this behavior.
  2. MySQL returned the last inserted row for compatibility with some brain-dead systems. (Does this make MySQL brain-dead? Well, maybe this particular behavior is a little brain-dead). This is controlled by the SQL_AUTO_IS_NULL server variable, which according to the manual,

    If set to 1 (the default), you can find the last inserted row for a table that contains an AUTO_INCREMENT column by using the following construct:

    WHERE auto_increment_column IS NULL

    This behavior is used by some ODBC programs, such as Access.

  3. MySQL only returns the last inserted row once; the next statement will return a sane result (LAST_INSERT_ID() does not have this limitation).

Bizarre, eh? However, any system that’s really used much in the real world will end up with these kinds of idiosyncrasies to meet particular needs. Oh, the joy of trying to be compatible with Microsoft Access!

Conclusion

Know thy MySQL Manual. I only discovered these things by accident. The good news is, the manual is really, really good; it has to be one of the best pieces of documentation I know. Now, if only innotop‘s manual were that good…

Written by Xaprb

May 31st, 2007 at 7:49 pm

Posted in Uncategorized

7 Responses to 'Why IS NULL doesn’t always work in MySQL'

Subscribe to comments with RSS

  1. Anonymous

    1 Jun 07 at 5:27 am

  2. That’s a good quick-reference. Thanks for the link. Though this part “In MySQL this behaviour is necessary, as it is the only way of accessing the AUTO_INCREMENT pseudo-sequence” is not correct; there is LAST_INSERT_ID().

    Xaprb

    1 Jun 07 at 6:29 am

  3. IMO, it should error out when you attempt to put a value in the auto increment field without first stating that you intended to do that (turn it off). That’s how SQL Server works, and is in all honesty, much more intuitive in this regard.

    Bill

    1 Jun 07 at 9:16 am

  4. Yes, I like SQL Server’s behavior better too. It’s an auto-generated number — it should have a big “can’t touch this” sign in front of it.

    Xaprb

    1 Jun 07 at 9:19 am

  5. [...] Why IS NULL doesn’t always work in MySQL at Xaprb How can a query like “SELECT * FROM tbl WHERE col IS NULL” return a row where the column has a (non-NULL) value? Read on to find out. [...]

  6. Very insightful. The question Baron is how long did it take you to work out the point 1,2 and 3.

    Obviously other factors like when in the day, what other fires and alcohol are all valid excuses to claim it took longer then you are prepared to admit.

    RTFM. Even I found the same yet again today in “Innodb Monitoring I didn’t know” — http://blog.arabx.com.au/?p=702

    Ronald Bradford

    1 Jun 07 at 6:58 pm

  7. Well, 2 and 3 were easy because I didn’t encounter them “in the wild” — I read about them in the manual accidentally. But #1, well, that one took me a while to understand. It was a weird failing test that ran in production but failed in the test environment, which was configured differently. Then again just a few days ago, my coworker ran into the same thing (because I accidentally mis-configured the test DB servers again) and it reminded me of it.

    Xaprb

    1 Jun 07 at 10:16 pm

Leave a Reply