Присоединение к самой последней записи на основе даты в другой записи - PullRequest
1 голос
/ 29 мая 2019

У меня есть две таблицы - назовем их week и contract, вот так:

Week                                    Contract    
emp_id | starting   | data1 |  ...   emp_id | from_date  | data2 | ...
-------|------------|-------|--      -------|------------|-------|--
12     | 2019-01-08 | abcd  |        12     | 2018-08-01 | efgh  | 
12     | 2019-01-15 | abcd  |        13     | 2018-10-02 | efgh  | 
12     | 2019-01-22 | abcd  |        13     | 2019-01-15 | ijkl  | 
13     | 2019-01-08 | abcd  |        13     | 2019-03-19 | mnop  | 
13     | 2019-01-15 | abcd  |        14     | 2017-02-02 | efgh  | 
13     | 2019-01-22 | abcd  |        15     | 2018-01-19 | efgh  | 

Поле week.starting - это дата (datetime со временем, установленным в полночь), которая находится на довольнорегулярные отрезки.Конкретная комбинация (emp_id, начальный) является уникальной.Поле from_date также является датой, в которой записывается начальный период, к которому применяется запись contract.Это может произойти в будущем, поэтому мы не можем просто сделать MAX(from) и получить правильный контракт для каждого сотрудника.В настоящее время (emp_id, from_date) является уникальным, но я не хочу на это полагаться.week.starting и contract.from_date могут быть идентичны.

Я хочу запрос, который возвращает всю запись week, и для каждой записи для того, что contract было активным в то время, то естьзапись, в которой from_date является наибольшей, но все же меньше или равна week.starting.Получение этого контракта, если у меня есть конкретная неделя, является довольно простой самой большой проблемой для каждой группы:

SELECT * FROM contract 
WHERE contract.emp_id = @emp_id AND contract.from_date <= @starting
ORDER BY contract.from_date DESC
LIMIT 1

Но я не могу понять, как это сделать, как часть запроса, чтобы получитькаждая запись в week.Моя конкретная комбинация препятствий означает, что я не смог найти ответ, несмотря на то, что это общий набор проблем.Похоже, я не могу передать week.starting в подзапрос, и я также не могу использовать LIMIT в объединении.До сих пор моя лучшая попытка заключалась в том, чтобы присоединиться ко всем контрактам, которые были меньше данной недели.

Какой запрос вернет искомый результат?

emp_id | starting   | from_date  | data1 | data2 | ...
-------|------------|------------|-------|-------|--
12     | 2019-01-08 | 2018-08-01 | abcd  | efgh  |
12     | 2019-01-15 | 2018-08-01 | abcd  | efgh  |
12     | 2019-01-22 | 2018-08-01 | abcd  | efgh  |
13     | 2019-01-08 | 2018-10-02 | abcd  | efgh  |
13     | 2019-01-15 | 2019-01-15 | abcd  | ijkl  |
13     | 2019-01-22 | 2019-01-15 | abcd  | ijkl  |

Ответы [ 2 ]

2 голосов
/ 29 мая 2019

Вы должны быть в состоянии использовать оконную функцию, чтобы упорядочивать контракты вовремя после фильтрации будущих контрактов и назначать ранг. Тогда вы можете выбрать последний с самым высоким рангом.

Не проверял это, но должно выглядеть примерно так:

select * from (
    select w.*, c.from_date, c.data2,
        row_number() over (partition by c.emp_id, w.starting order by c.from_date desc) as latest
    from week w
    join contract c on c.emp_id = w.emp_id and c.from_date <= w.starting
) as sub where latest = 1
1 голос
/ 29 мая 2019

В Postgres вы можете использовать боковое соединение:

select w.*, c.*
from weeks w left join lateral
     (select c.*
      from contract c
      where c.emp_id = w.emp_id and
            c.from_date <= w.starting
      order by c.from_date desc
      fetch first 1 row only
     ) c;
...