2015-01-29 2 views
1

Извините за запутанное название, но это лучший способ объяснить это. Это не обычная проблема «последних из группы», и я не смог найти что-либо подобное в Интернете.MySQL: получите самую старую запись из последней группы

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

ID, start_date, person_ID, location_ID, status 
1, 2014-10-12, 1,   1,   job a 
2, 2014-10-13, 2,   2,   job b 
3, 2014-10-15, 1,   3,   job c 
4, 2014-10-21, 1,   3,   job d 
5, 2014-10-22, 2,   4,   job a 
6, 2014-10-26, 2,   2,   job d 

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

person_ID, location_ID, since 
1,   3,   2014-10-15 
2,   2,   2014-10-26 

Получение, когда они начали текущая работа относительно легко, присоединившись к max (start_date), но мне нужен min (start_date) из заданий, выполненных в самом последнем месте.

Я пытаюсь присоединиться к min (start_date) в записях, которые соответствуют текущему местоположению (из самой последней записи), и это отлично работает, пока у меня не будет человека (например, человека 2), который имеет несколько посещений текущее местоположение ... вы можете увидеть в моих желаемых результатах, что мне нужна дата 10-26, а не 10-13, которая впервые была на сайте.

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

+0

Так почему 2014-10-15 для человека с идентификатором 1 вместо 2014-10-21 –

+0

Потому что они прибыли на сайт 3 на 2014-10-15 годы и остались там, чтобы начать работу d в 2014-10-21. Запрос заключается в размещении наших сервисных техников, поэтому мне нужно знать, когда они прибыли на сайт, независимо от выполняемых работ. – whiteatom

ответ

1

Если я понимаю, что вы спрашиваете правильно, вы можете использовать EXISTS, чтобы устранить все, кроме самых последних местоположений на человека, и получить минимальную дату из полученных строк.

SELECT person_id, location_id, MIN(start_date) since 
FROM status s 
WHERE NOT EXISTS (
    SELECT 1 FROM status 
    WHERE s.person_id = person_id 
    AND s.location_id <> location_id 
    AND s.start_date < start_date) 
GROUP BY person_id 

An SQLfiddle to test with.

В основном, он устраняет все местоположения и время, когда тот же человек недавно посетил другое место. Например;

1, 2014-10-12, 1,   1,   job a 

... исключается, так как человек 1 посетил местонахождение 3 совсем недавно;

3, 2014-10-15, 1,   3,   job c 

...сохраняется, поскольку тот же человек недавно посетил одно и то же место совсем недавно.

Затем он выбирает наименее последнее время на человека. Поскольку сохранены только строки из последнего местоположения, это будет самое последнее время из самого последнего места.

+0

Удивительно .. это похоже на работу - но я не уверен, почему. Как не существует того, что кто-то идет на сайт, переходя на другой сайт, а затем обратно? В приведенной выше таблице примеров для человека 2 не будет ли существовать возвратная строка 2 и 6, а затем вернуть дату из строки 2 (являющейся минимальной)? – whiteatom

+0

Я не могу сломать это .. поэтому я думаю, что у вас есть это сэр. Как я уже сказал выше, я был бы признателен, если бы вы могли сказать мне, как это происходит, поэтому я могу с уверенностью утверждать. Я вижу, что ваш подзапрос находит все, что устраняет все другие местоположения (тот же самый другой сайт) .. поэтому я думаю, что s.start_date whiteatom

+0

@whiteatom Я сделал попытку быстрого объяснения, дайте мне знать, если это неясно, и я обновлю его, когда у меня будет больше времени :) –

1

Я думаю, что самый простой способ с переменными, чтобы следить за информацией, необходимой:

select person_id, location_id, min(start_date) as since 
from (select s.*, 
      (@rn := if(@p <> person_id, if(@p:=person_id, 1, 1), 
         if(@l = location_id, @rn, 
          if(@l:=location_d, @rn + 1, @rn + 1) 
         ) 
         ) 
      ) as location_counter 
     from status s cross join 
      (select @p := 0, @l := 0, @rn := 0) vars 
     order by person_id, start_date desc 
    ) s 
where location_counter = 1 
group by person_id, location_id; 

Странная логика с переменными (пытается) перечислить места для каждого человека. Он должен увеличивать значение @rn только тогда, когда местоположение меняет и возвращает значение 1 для нового человека.

+0

Я боялся, что это может превратиться в переменные. Время, чтобы сделать некоторые чтения ... – whiteatom

-1

Довольно простой на самом деле.

SELECT g.person_ID, 
    (SELECT l.location_ID 
    FROM status l 
    WHERE l.person_ID = g.person_ID 
    AND l.start_date = MAX(g.start_date)) AS location, 
    MAX(g.start_date) AS since 
FROM status g 
GROUP BY g.person_ID 

Это использует группировку на person_ID и использует выражение SELECT для выражения столбца местоположения.

Единственный вопрос: имеете ли вы значение MIN i.o. MAX, так как в вашем примере вы даете самую младшую дату, а не самую старую.

+0

Спасибо за ответ, но это не нужно мне нужно. Вы предлагаете решение «max per group». Мне нужна дата, когда они прибыли в текущее местоположение - если самые последние строки имеют одинаковое расположение, мне нужен первый из текущего «кластера» строк. – whiteatom

Смежные вопросы