Получить записи с максимальным значением для каждой группы на основе второй таблицы - PullRequest
0 голосов
/ 14 января 2019

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

Допустим, у меня есть пара зданий, в каждом здании есть несколько офисов, и у меня есть люди, которые "регистрируются" в этих офисах для работы.

Эта таблица, называемая «офисы», сопоставляет здания с офисами:

building   office
---
Seuss      Yertle
Seuss      Cubbins
Milne      Pooh
Milne      Eeyore
Milne      Roo

Эта таблица, называемая "checkins", записывает, когда люди работали в каждом офисе:

id   office   person   timestamp
---
1    Yertle   Aaron    100
2    Cubbins  Aaron    200
3    Pooh     Aaron    300
4    Cubbins  Charlie  300
5    Cubbins  Aaron    700
6    Eeyore   Beth     600
7    Pooh     Beth     400

Я хотел бы сгенерировать таблицу, в которой сообщалось бы для каждого комбо здания с человеком, чья регистрация была самой последней для этого человека в этом здании:

 building  person   checkin_id  office   timestamp
 ---
 Seuss     Aaron    5           Cubbins  700
 Milne     Aaron    3           Pooh     300
 Milne     Beth     6           Eeyore   600
 Seuss     Charlie  4           Cubbins  300

Я в недоумении, как мне это сделать. Стандартный трюк заключается в соединении таблицы с самим собой при сравнении соответствующего значения, а затем отбрасывании строк, где нет большего значения. Я предполагаю, что мне понадобятся две копии "checkins" и две копии "зданий" со сложным соединением между ними, но я не могу заставить NULL отображаться в правильном месте.

Я использую MySQL, если это поможет.

Ответы [ 3 ]

0 голосов
/ 14 января 2019

Чтобы получить желаемый результат, вы должны создать таблицу, в которой есть все чекины в каждом офисе (JOIN offices до checkins), а затем JOIN в таблицу последних чеков для каждого человек в каждом здании:

SELECT o.building, c.person, c.id AS checkin_id, c.office, c.timestamp
FROM offices o
JOIN checkins c ON c.office = o.office
JOIN (SELECT o.building, c.person, MAX(c.timestamp) AS timestamp
      FROM offices o
      JOIN checkins c ON c.office = o.office
      GROUP BY o.building, c.person) t ON t.building = o.building AND t.person = c.person AND t.timestamp = c.timestamp
ORDER BY c.person, c.office

Выход:

building    person      checkin_id  office      timestamp
Seuss       Aaron       5           Cubbins     700
Milne       Aaron       3           Pooh        300
Milne       Beth        6           Eeyore      600
Seuss       Charlie     4           Cubbins     300

Демонстрация по dbfiddle

0 голосов
/ 14 января 2019

Существует трюк с использованием group_concat() и substring_index(), который позволяет вам сделать это с одним group by:

select o.building, c.person,
       max(c.id) as checkinid,
       substring_index(group_concat(c.office order by timestamp desc), ',', 1) as office,
       max(c.timestamp) as timestamp
from offices o join
     checkins c
     on o.office = c.office
group by o.building, c.person;

В этой версии предполагается, что id и timestamp увеличиваются вместе, поэтому max() может использоваться для обоих.

Кроме того, group_concat() - по умолчанию - имеет ограничение около 1000 символов для промежуточного результата, поэтому это не будет работать, если есть много и много офисов для комбинации человек / здание или если офисы есть длинные имена. Разумеется, разделитель можно изменить, если в имени office появятся запятые.

0 голосов
/ 14 января 2019

использовать связанный подзапрос

 select b.* from
  (select o.building,c.person,c.id as checkinid,
   c.office,c.timestamp from
   offices o join checkins c
   on o.office=c.office
  ) b
  where b.timestamp = (select max(a.timestamp)
                      from (
                        select o.building,c.person,
                        c.office,c.timestamp from
                        offices o join checkins c
                        on o.office=c.office
                         ) as a  where a.building=b.building and  
                     a.person=b.person 
                   )
       order by person

выход

building    person  checkinid   office  timestamp
Milne       Aaron     3         Pooh     300
Seuss       Aaron     5         Cubbins  700
Milne       Beth      6         Eeyore   600
Seuss       Charlie   4         Cubbins  300
...