Выберите самые ранние дату и время из списка отдельных пользовательских сессий - PullRequest
3 голосов
/ 22 сентября 2009

У меня есть таблица сессий доступа пользователей, в которой записывается активность посетителей сайта:

accessid, userid, date, time, url

Я пытаюсь получить все отдельные сеансы для идентификатора пользователя 1234, а также самую раннюю дату и время для каждого из этих отдельных сеансов.

SELECT 
    DISTINCT accessid, 
    date, 
    time 
FROM 
    accesslog 
WHERE userid = '1234' 
GROUP BY accessid

Это дает мне дату и время случайной строки в каждом отдельном accessid. Я прочитал несколько постов, рекомендующих использовать min () и max (), поэтому я попытался:

SELECT DISTINCT accessid, MIN(DATE) AS date, MIN(TIME) AS time FROM accesslog WHERE userid = '1234' GROUP BY accessid ORDER BY date DESC, time DESC

... и даже ...

SELECT DISTINCT accessid, MIN(CONCAT(DATE, ' ', TIME)) AS datetime FROM accesslog WHERE userid = '1234' GROUP BY accessid ORDER BY date DESC, time DESC

... но я никогда не получу правильный результат с самой ранней даты и времени.

В чем заключается хитрость при заказе запроса такого типа?

РЕДАКТИРОВАТЬ -

Что-то странное происходит ...

Код, опубликованный ниже Биллом Карвином, правильно извлекает самую раннюю дату и время для сеансов, которые начались в 2009-09 годах. Но для сеансов, начавшихся в один прекрасный день в 2009-08 годах, время и дата первого попадания в текущем месяце - это то, что возвращается. Другими словами, запрос не охватывает месяцы!

Пример набора данных:

accessid    | userid    | date          | time
1           | 1234      | 2009-08-15    | 01:01:01
1           | 1234      | 2009-09-01    | 12:01:01
1           | 1234      | 2009-09-15    | 13:01:01
2           | 1234      | 2009-09-01    | 14:01:01
2           | 1234      | 2009-09-15    | 15:01:01

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

accessid    | userid    | date          | time
1           | 1234      | 2009-09-01    | 12:01:01
2           | 1234      | 2009-09-01    | 14:01:01

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

Я схожу с ума?

РЕДАКТИРОВАТЬ 2 -

Ответ - да, я схожу с ума. Запрос работает с приведенными выше примерами данных, если поместить их в таблицу с дублированной структурой.

Вот (усеченные) исходные данные. Я включил самый первый хит, еще один хит в том же месяце, первый хит следующего месяца, а затем последний хит месяца. Исходный набор данных имеет гораздо больше попаданий между этими точками, в общей сложности 462 строки.

accessid                            | date          | time
cbb82c08d3103e721a1cf0c3f765a842    | 2009-08-18    | 04:01:42
cbb82c08d3103e721a1cf0c3f765a842    | 2009-08-23    | 23:18:52
cbb82c08d3103e721a1cf0c3f765a842    | 2009-09-17    | 05:12:16
cbb82c08d3103e721a1cf0c3f765a842    | 2009-09-18    | 06:29:59

... запрос возвращает значение 2009-09-17 в качестве самого раннего значения при запросе исходной таблицы. Но когда я копирую ........ о, шары.

Это потому, что попадания с 2009-08% имеют пустое поле userid.

Ответы [ 2 ]

4 голосов
/ 22 сентября 2009

Это разновидность проблемы «наибольший n на группу», которая возникает в StackOverflow несколько раз в неделю.

SELECT 
        a1.accessid, 
        a1.date, 
        a1.time 
FROM 
        accesslog a1
LEFT OUTER JOIN
        accesslog a2
  ON (a1.accessid = a2.accessid AND a1.userid = a2.userid
    AND (a1.date > a2.date OR a1.date = a2.date AND a1.time > a2.time))
WHERE a1.userid = '1234'
  AND a2.accessid IS NULL;

Способ, которым это работает, состоит в том, что мы пытаемся найти строку (a2), которая имеет тот же accessid и userid, и более раннюю дату или время, чем строка a1. Когда мы не можем найти более раннюю строку, тогда a1 должен быть самой ранней строкой.


Re ваш комментарий, я только что попробовал с примерами данных, которые вы предоставили. Вот что я получаю:

+----------+------------+----------+
| accessid | date       | time     |
+----------+------------+----------+
|        1 | 2009-08-15 | 01:01:01 | 
|        2 | 2009-09-01 | 14:01:01 | 
+----------+------------+----------+

Я использую MySQL 5.0.75 на Mac OS X.

0 голосов
/ 22 сентября 2009

Попробуйте это

SELECT 
    accessid, 
    date, 
    time 
FROM 
    accesslog 
WHERE userid = '1234' 
GROUP BY accessid
HAVING MIN(date)

Он вернет все уникальные обращения с минимальным временем для каждого для userid = '1234'.

...