user1094786
user1094786

Reputation: 6800

MySQL Left Join and NULL columns from right table

I have the following two MySQL tables which I need to join:

CREATE TABLE `tbl_L` (
  `datetime` datetime NOT NULL,
  `value` decimal(14,8) DEFAULT NULL,
  `series_id` int(11) NOT NULL,
  PRIMARY KEY (`series_id`,`datetime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

CREATE TABLE `tbl_R` (
  `datetime` datetime NOT NULL,
  `value` decimal(14,8) DEFAULT NULL,
  `series_id` int(11) NOT NULL,
  PRIMARY KEY (`series_id`,`datetime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

I need to select all the dates and values from tbl_L, but also the values in tbl_R that have the same datetime as an entry in tbl_L. A trivial join, like so:

SELECT tbl_L.datetime AS datetime, tbl_L.value AS val_L, tbl_R.value AS val_R 
FROM tbl_L 
    LEFT JOIN tbl_R 
        ON tbl_L.datetime = tbl_R.datetime
WHERE 
   tbl_L.series_id = 1 AND tbl_R.series_id = 2 ORDER BY tbl_L.datetime ASC

Won't work because it will only return datetime that are both in tbl_L and tbl_R (because the right table is mentioned in the WHERE clause).

Modifying the query to look like this:

SELECT tbl_L.datetime AS datetime, tbl_L.value AS val_L, tbl_R.value AS val_R 
FROM tbl_L 
    LEFT JOIN tbl_R 
        ON tbl_L.datetime = tbl_R.datetime 
           AND tbl_R.series_id = 2 
           AND tbl_L.series_id = 1
ORDER BY tbl_L.datetime ASC;

Significantly slows it down (from a few milliseconds to a few long seconds).

Edit: and also doesn't actually work. I will clarify what I need to achieve:

Assume the following data in the tables:

mysql> SELECT * FROM tbl_R;
+---------------------+------------+-----------+
| datetime            | value      | series_id |
+---------------------+------------+-----------+
| 2013-02-20 19:21:00 | 5.87000000 |         2 |
| 2013-02-20 19:22:00 | 5.90000000 |         2 |
| 2013-02-20 19:23:00 | 5.80000000 |         2 |
| 2013-02-20 19:25:00 | 5.65000000 |         2 |
+---------------------+------------+-----------+
4 rows in set (0.00 sec)

mysql> SELECT * FROM tbl_L;
+---------------------+-------------+-----------+
| datetime            | value       | series_id |
+---------------------+-------------+-----------+
| 2013-02-20 19:21:00 | 13.16000000 |         1 |
| 2013-02-20 19:23:00 | 13.22000000 |         1 |
| 2013-02-20 19:24:00 | 13.14000000 |         1 |
| 2013-02-20 19:25:00 | 13.04000000 |         1 |
+---------------------+-------------+-----------+
4 rows in set (0.00 sec)

Again, I need all entries in tbl_L joined with the entries in tbl_R that match in terms of datetime, otherwise NULL.

My output should look like this:

+---------------------+-------------+-------------+
| datetime            | val_L       | val_R       |
+---------------------+-------------+-------------+
| 2013-02-20 19:21:00 | 13.16000000 | 5.870000000 |
| 2013-02-20 19:23:00 | 13.22000000 | 5.800000000 |
| 2013-02-20 19:24:00 | 13.14000000 | NULL        |
| 2013-02-20 19:25:00 | 13.04000000 | 5.650000000 |
+---------------------+-------------+-------------+

Thanks again!

Upvotes: 3

Views: 5295

Answers (1)

G-Nugget
G-Nugget

Reputation: 8836

You can get the data you want by moving only the condition for tbl_R into the join's ON clause like this:

SELECT tbl_L.datetime AS datetime, tbl_L.value AS val_L, tbl_R.value AS val_R 
FROM tbl_L 
LEFT JOIN tbl_R 
    ON tbl_L.datetime = tbl_R.datetime
        AND tbl_R.series_id = 2
WHERE 
tbl_L.series_id = 1 ORDER BY tbl_L.datetime ASC

Also, there is no index for the query to use on tbl_L. Adding an index on tbl_L.series_id will help the query's performance.

Upvotes: 4

Related Questions