Bug #1473 "Union" seems to replace "null" with "zero"
Submitted: 3 Oct 2003 9:30 Modified: 10 Dec 2003 19:13
Reporter: Andrew Carlon Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server Severity:S3 (Non-critical)
Version:4.0.15 OS:Linux (linux-intel)
Assigned to: Michael Widenius CPU Architecture:Any

[3 Oct 2003 9:30] Andrew Carlon
Description:
When I try to union two tables, it seems to replace "null" with 0's in columns of type "int".

How to repeat:
-- MySQL dump 9.09
--
-- Host: localhost    Database: test
---------------------------------------------------------
-- Server version       4.0.15-standard

--
-- Table structure for table `bar`
--

CREATE TABLE bar (
  id int(4) default NULL,
  date date default NULL,
  bar_data int(4) default NULL
) TYPE=MyISAM;

--
-- Dumping data for table `bar`
--

INSERT INTO bar VALUES (1,'2001-01-01',1);
INSERT INTO bar VALUES (1,'2002-02-02',2);
INSERT INTO bar VALUES (2,'2002-02-01',22);

--
-- Table structure for table `foo`
--

CREATE TABLE foo (
  id int(4) default NULL,
  date date default NULL,
  foo_data int(4) default NULL
) TYPE=MyISAM;

--
-- Dumping data for table `foo`
--

INSERT INTO foo VALUES (1,'2001-01-02',3);
INSERT INTO foo VALUES (1,'2002-02-05',25);
INSERT INTO foo VALUES (2,'2001-02-22',15);

Ordinarily I would run the following query:

mysql> select id, date, null as foo_data, bar_data from bar
    -> union
    -> select id, date, foo_data, null as bar_data from foo;

hoping for the following table:

+------+------------+----------+----------+
| id   | date       | foo_data | bar_data |
+------+------------+----------+----------+
|    1 | 2001-01-01 | NULL     |        1 |
|    1 | 2002-02-02 | NULL     |        2 |
|    2 | 2002-02-01 | NULL     |       22 |
|    1 | 2001-01-02 | 3        |     NULL |
|    1 | 2002-02-05 | 25       |     NULL |
|    2 | 2001-02-22 | 15       |     NULL |
+------+------------+----------+----------+
6 rows in set (0.00 sec)

But I know that this would actually result in

+------+------------+----------+----------+
| id   | date       | foo_data | bar_data |
+------+------------+----------+----------+
|    1 | 2001-01-01 | NULL     |        1 |
|    1 | 2002-02-02 | NULL     |        2 |
|    2 | 2002-02-01 | NULL     |       22 |
|    1 | 2001-01-02 |          |     NULL |
|    1 | 2002-02-05 |          |     NULL |
|    2 | 2001-02-22 |          |     NULL |
+------+------------+----------+----------+
6 rows in set (0.00 sec)

because the foo_data column's type is set by the first select clause (where foo_data is null).  So, taking a tip I found in the comments in the manual, I add another select clause, as follows:

mysql> select id, date, 8888 as foo_data, 8888 as bar_data from foo where 1 = 0
    -> union
    -> select id, date, null as foo_data, bar_data from bar
    -> union
    -> select id, date, foo_data, null as bar_data from foo;

which gives the following table:

+------+------------+----------+----------+
| id   | date       | foo_data | bar_data |
+------+------------+----------+----------+
|    1 | 2001-01-01 |        0 |        1 |
|    1 | 2002-02-02 |        0 |        2 |
|    2 | 2002-02-01 |        0 |       22 |
|    1 | 2001-01-02 |        3 |        0 |
|    1 | 2002-02-05 |       25 |        0 |
|    2 | 2001-02-22 |       15 |        0 |
+------+------------+----------+----------+
6 rows in set (0.00 sec)

The nulls have been replaced by zero's!

If foo_data and bar_data are varchar(4) instead of int(4), and '    ' is used instead of 8888, then the nulls are replaced with what appear to be empty strings.
[3 Oct 2003 11:32] Indrek Siitan
Thanks for a good bug report.

According to Peter Gulutzan, our SQL standards expert:
"If any of the selects is nullable, then the result should be nullable."

So I'm marking this as a verified bug.
[10 Dec 2003 19:13] Michael Widenius
Thank you for your bug report. This issue has already been fixed
in the latest released version of that product, which you can download at 
http://www.mysql.com/downloads/

Additional info:

The reson for this is that in MySQL 4.0 it is the first select list that defines the types of the tables.  We can't easily fix this without a big code change.

MySQL 4.1.1 does however handle this correctly.