whiteatom
whiteatom

Reputation: 1455

Join most recent record before time in primary table

I know the "how to join the newest record" questions get asked a lot, however, this one exceeds my knowledge. I usually use a "join the max date subquery and then join the row with the matching id and time" approach to the problem, and I can add additional conditions in the where clause of the subquery, but this style doesn't work in this situation.

I am looking for a history of all records in the first table, and to join on the most recent record from the second table before the time of the record from the first.

Example:

CREATE TABLE `A` (
  `id` int(11) NOT NULL,
  `a_time` timestamp NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `A` (`id`, `a_time`) VALUES
(1, '2018-03-21 04:30:00'),
(2, '2018-03-21 05:30:00'),
(3, '2018-03-21 07:30:00'),
(4, '2018-03-21 12:30:00');

CREATE TABLE `B` (
  `id` int(11) NOT NULL,
  `b_time` timestamp NOT NULL,
  `some_text` varchar(128) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `B` (`id`, `b_time`, `some_text`) VALUES
(1, '2018-03-21 05:30:00', 'Foo'),
(2, '2018-03-21 09:30:00', 'Bar');


ALTER TABLE `A`
  ADD PRIMARY KEY (`id`);

ALTER TABLE `B`
  ADD PRIMARY KEY (`id`);

What I'm hoping for is the id and time from A, and the most recent (<=) some_text from B

a.id a.a_time            b.some_text
------------------------------------
1    2018-03-21 04:30:00 null
2    2018-03-21 05:30:00 Foo
3    2018-03-21 07:30:00 Foo
4    2018-03-21 12:30:00 Bar

Can someone help me out with this one? Thanks!

Upvotes: 0

Views: 23

Answers (2)

Strawberry
Strawberry

Reputation: 33945

I might use an uncorellated subquery, like this:

SELECT x.some
     , c.columns
     , y.some_column
  FROM 
     ( SELECT a.*
            , MAX(b.b_time) b_time 
         FROM a
         LEFT 
         JOIN b 
           ON b.b_time <= a.a_time 
        GROUP 
           BY id
     ) x 
  LEFT 
  JOIN b y 
    ON y.something = x.something;
+----+---------------------+-----------+
| id | a_time              | some_text |
+----+---------------------+-----------+
|  1 | 2018-03-21 04:30:00 | NULL      |
|  2 | 2018-03-21 05:30:00 | Foo       |
|  3 | 2018-03-21 07:30:00 | Foo       |
|  4 | 2018-03-21 12:30:00 | Bar       |
+----+---------------------+-----------+

Upvotes: 1

Paul Maxwell
Paul Maxwell

Reputation: 35583

I would use a "correlated subquery" like this:

Query 1:

select
       a.*
    , (select b.some_text from b
       where b.b_time <= a.a_time
       order by b.b_time DESC
       limit 1) as some_text
from a
order by a.id

Results:

| id |               a_time | some_text |
|----|----------------------|-----------|
|  1 | 2018-03-21T04:30:00Z |    (null) |
|  2 | 2018-03-21T05:30:00Z |       Foo |
|  3 | 2018-03-21T07:30:00Z |       Foo |
|  4 | 2018-03-21T12:30:00Z |       Bar |

Upvotes: 1

Related Questions