Bug #51521 MERGE Algorithm in LEFT JOIN retuns 0000-00-00 instead of NULL
Submitted: 25 Feb 2010 18:03 Modified: 26 Feb 2010 8:16
Reporter: Drew Vogel Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S2 (Serious)
Version:5.1.42, 5.1.45-bzr OS:Any
Assigned to: CPU Architecture:Any
Tags: date, datetime, merge, null, Views, zero
Triage: Triaged: D2 (Serious)

[25 Feb 2010 18:03] Drew Vogel
Description:
I created a view to calculate a DATE field from separate numeric Year/Month/Day fields, eliminating invalid dates. When I join this view back to the original table, using a left join, I expect the DOB field on the right side of the join to be NULL where the join condition is false. However it returns 0000-00-00. This behavior is observed while using the MERGE algorithm but not while using the TEMPTABLE algorithm.

How to repeat:
DROP TABLE IF EXISTS `p9629`.`gtowey_test`;
CREATE TABLE  `p9629`.`gtowey_test` (
  `id` varchar(12) NOT NULL,
  `Birthdate_Year` int(4) default NULL,
  `Birthdate_Day` int(2) default NULL,
  `Birthdate_Month` int(2) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

SELECT * FROM gtowey_test;
-- This returns:
-- '12345678', 1960, 1, 1
-- '87654321', 1985, 31, 12
-- '00000000', 0, 0, 0
-- as expected

SELECT
  id,
  str_to_date(CONCAT_WS('-', Birthdate_Year, Birthdate_Month, Birthdate_Day), '%Y-%m-%d') as DOB
FROM   `gtowey_test`
WHERE
    id IS NOT NULL
AND Birthdate_Year IS NOT NULL
AND Birthdate_Month IS NOT NULL
AND Birthdate_Day IS NOT NULL
AND Birthdate_Year <> 0
AND Birthdate_Month <> 0
AND Birthdate_Day <> 0;
-- This returns:
-- '12345678', '1960-01-01'
-- '87654321', '1985-12-31'
-- as expected

-- Now I want to join it back to the original table to bring in other fields
-- So let's make a view out of it
CREATE OR REPLACE ALGORITHM=MERGE VIEW gtowey_test_dob AS
SELECT
  id,
  str_to_date(CONCAT_WS('-', Birthdate_Year, Birthdate_Month, Birthdate_Day), '%Y-%m-%d') as DOB
FROM   `gtowey_test`
WHERE
    id IS NOT NULL
AND Birthdate_Year IS NOT NULL
AND Birthdate_Month IS NOT NULL
AND Birthdate_Day IS NOT NULL
AND Birthdate_Year <> 0
AND Birthdate_Month <> 0
AND Birthdate_Day <> 0;

SELECT * FROM gtowey_test_dob;
-- This view returns the same results:
-- '12345678', '1960-01-01'
-- '87654321', '1985-12-31'

SELECT
  id,
  Birthdate_Year,
  DOB
FROM gtowey_test
LEFT JOIN gtowey_test_dob USING (id);
-- This returns:
-- '00000000', '0000-00-00'
-- '12345678', '1960-01-01'
-- '87654321', '1985-12-31'
-- Notice the 0000-00-00

-- Let's try the left join to a sub-select instead of the view:
SELECT
  id,
  DOB
FROM gtowey_test
LEFT JOIN (
  SELECT
    id,
    str_to_date(CONCAT_WS('-', Birthdate_Year, Birthdate_Month, Birthdate_Day), '%Y-%m-%d') as DOB
  FROM   `gtowey_test`
  WHERE
      id IS NOT NULL
  AND Birthdate_Year IS NOT NULL
  AND Birthdate_Month IS NOT NULL
  AND Birthdate_Day IS NOT NULL
  AND Birthdate_Year <> 0
  AND Birthdate_Month <> 0
  AND Birthdate_Day <> 0) as gtowey_test_dob USING (id);

-- This returns the DOB as NULL, like I'd expect it the view to:
-- '00000000', NULL
-- '12345678', '1960-01-01'
-- '87654321', '1985-12-31'
[26 Feb 2010 8:16] Valeriy Kravchuk
Thank you for the problem report. Verified just as described with recent 5.1.45 from bzr:

openxs@suse:/home2/openxs/dbs/5.1> bin/mysql -uroot test
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.1.45-debug Source distribution

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create database p9629;
Query OK, 1 row affected (0.01 sec)

mysql> use p9629;
Database changed
mysql> CREATE TABLE  `p9629`.`gtowey_test` (
    ->   `id` varchar(12) NOT NULL,
    ->   `Birthdate_Year` int(4) default NULL,
    ->   `Birthdate_Day` int(2) default NULL,
    ->   `Birthdate_Month` int(2) default NULL,
    ->   PRIMARY KEY  (`id`)
    -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Query OK, 0 rows affected (0.02 sec)

mysql> insert into gtowey_test
    -> values ('12345678', 1960, 1, 1);
Query OK, 1 row affected (0.01 sec)

mysql> insert into gtowey_test values ('87654321', 1985, 31, 12);
Query OK, 1 row affected (0.00 sec)

mysql> insert into gtowey_test values ('00000000', 0, 0, 0);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM gtowey_test;
+----------+----------------+---------------+-----------------+
| id       | Birthdate_Year | Birthdate_Day | Birthdate_Month |
+----------+----------------+---------------+-----------------+
| 12345678 |           1960 |             1 |               1 |
| 87654321 |           1985 |            31 |              12 |
| 00000000 |              0 |             0 |               0 |
+----------+----------------+---------------+-----------------+
3 rows in set (0.00 sec)

mysql> SELECT
    ->   id,
    ->   str_to_date(CONCAT_WS('-', Birthdate_Year, Birthdate_Month, Birthdate_Day), '%Y-%m-%d')
    -> as DOB
    -> FROM   `gtowey_test`
    -> WHERE
    ->     id IS NOT NULL
    -> AND Birthdate_Year IS NOT NULL
    -> AND Birthdate_Month IS NOT NULL
    -> AND Birthdate_Day IS NOT NULL
    -> AND Birthdate_Year <> 0
    -> AND Birthdate_Month <> 0
    -> AND Birthdate_Day <> 0;
+----------+------------+
| id       | DOB        |
+----------+------------+
| 12345678 | 1960-01-01 |
| 87654321 | 1985-12-31 |
+----------+------------+
2 rows in set (0.00 sec)

mysql> CREATE OR REPLACE ALGORITHM=MERGE VIEW gtowey_test_dob AS
    -> SELECT
    ->   id,
    ->   str_to_date(CONCAT_WS('-', Birthdate_Year, Birthdate_Month, Birthdate_Day), '%Y-%m-%d')
    -> as DOB
    -> FROM   `gtowey_test`
    -> WHERE
    ->     id IS NOT NULL
    -> AND Birthdate_Year IS NOT NULL
    -> AND Birthdate_Month IS NOT NULL
    -> AND Birthdate_Day IS NOT NULL
    -> AND Birthdate_Year <> 0
    -> AND Birthdate_Month <> 0
    -> AND Birthdate_Day <> 0;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM gtowey_test_dob;
+----------+------------+
| id       | DOB        |
+----------+------------+
| 12345678 | 1960-01-01 |
| 87654321 | 1985-12-31 |
+----------+------------+
2 rows in set (0.00 sec)

mysql> SELECT
    ->   id,
    ->   Birthdate_Year,
    ->   DOB
    -> FROM gtowey_test
    -> LEFT JOIN gtowey_test_dob USING (id);
+----------+----------------+------------+
| id       | Birthdate_Year | DOB        |
+----------+----------------+------------+
| 12345678 |           1960 | 1960-01-01 |
| 87654321 |           1985 | 1985-12-31 |
| 00000000 |              0 | 0000-00-00 |
+----------+----------------+------------+
3 rows in set (0.00 sec)

mysql> SELECT
    ->   id,
    ->   DOB
    -> FROM gtowey_test
    -> LEFT JOIN (
    ->   SELECT
    ->     id,
    ->     str_to_date(CONCAT_WS('-', Birthdate_Year, Birthdate_Month, Birthdate_Day),
    -> '%Y-%m-%d') as DOB
    ->   FROM   `gtowey_test`
    ->   WHERE
    ->       id IS NOT NULL
    ->   AND Birthdate_Year IS NOT NULL
    ->   AND Birthdate_Month IS NOT NULL
    ->   AND Birthdate_Day IS NOT NULL
    ->   AND Birthdate_Year <> 0
    ->   AND Birthdate_Month <> 0
    ->   AND Birthdate_Day <> 0) as gtowey_test_dob USING (id);
+----------+------------+
| id       | DOB        |
+----------+------------+
| 00000000 | NULL       |
| 12345678 | 1960-01-01 |
| 87654321 | 1985-12-31 |
+----------+------------+
3 rows in set (0.01 sec)