Есть немного объяснений, чтобы пойти с этим ответом - фактический запрос, который вы ищете, находится внизу.
Это пример выбора не только max / min-field-per-group, но и других соответствующих ему полей.
Канонический способ сделать это - LEFT JOIN
Приготовление стола к себе.Например, чтобы выбрать всю строку, соответствующую самому последнему соединению из CONNECTIONS
, вы должны сделать:
SELECT c.userid, c.tzid as latestTZ, c.dateconn as latestConn
FROM CONNECTIONS c
LEFT JOIN CONNECTIONS c2 ON c.userid=c2.userid AND c.dateconn<c2.dateconn
WHERE c2.dateconn IS NULL
ORDER BY c.userid;
Это, по существу, присоединяет CONNECTIONS
к себе на userid
и формирует все возможныепара дат подключения в пределах этого идентификатора пользователя, где c.dateconn<c2.dateconn
.Если в c2
нет строки, которая имеет большую дату, чем c
, то вы выбрали самую большую (т.е. самую последнюю) дату.JOIN
гарантирует, что вы также выбираете остаток соответствующей строки из таблицы.
Имея это в виду, именно так мы бы выбрали первую дату подключения и метку для каждого пользователя (с NULL
если они никогда не подключались. Если вы не хотите, чтобы это поведение (то есть показывало только пользователей, которые подключились), то вы можете полностью игнорировать таблицу USERS
.
SELECT u.id,c.dateconn as firstConnection,TZ.label AS firstTZ
FROM USERS u
LEFT JOIN CONNECTIONS c ON u.id=c.userid
LEFT JOIN CONNECTIONS c2 ON c.userid=c2.userid AND c.dateconn > c2.dateconn
LEFT JOIN TZ ON c.tzid=TZ.id
WHERE c2.dateconn IS NULL;
Чтобы выбрать последнюю версиюто же самое, за исключением того, что вы поменяете >
на <
:
SELECT u.id,c.dateconn as latestConnection,TZ.label AS latestTZ
FROM USERS u
LEFT JOIN CONNECTIONS c ON u.id=c.userid
LEFT JOIN CONNECTIONS c2 ON c.userid=c2.userid AND c.dateconn < c2.dateconn
LEFT JOIN TZ ON c.tzid=TZ.id
WHERE c2.dateconn IS NULL;
Ваш запрос немного сложнее, так как вы хотите выбрать не только min или max, но оба мин. и макс.
Решение
Я думаю, что вы могли бы UNION
предыдущие два запроса, ИЛИ вы могли бы сделать этовсе в один фол ударили, по сути, JOIN
- объединяя два запроса:
# MIN & MAX
SELECT u.id, c.dateconn as firstCon, TZ.label as firstTZ,
c3.dateconn as latestCon, TZ2.label as latestTZ
FROM USERS u
LEFT JOIN CONNECTIONS c ON u.id=c.userid
LEFT JOIN CONNECTIONS c2 ON c.userid=c2.userid AND c.dateconn > c2.dateconn
LEFT JOIN CONNECTIONS c3 ON c.userid=c3.userid AND c3.dateconn >= c.dateconn
LEFT JOIN CONNECTIONS c4 ON c3.userid=c4.userid AND c3.dateconn < c4.dateconn
LEFT JOIN TZ ON TZ.id=c.tzid
LEFT JOIN TZ TZ2 ON TZ2.id=c3.tzid
WHERE c2.dateconn IS NULL
AND c4.dateconn IS NULL
ORDER BY u.id;
Пара (c,c2)
находит первую дату / часовой пояс соединения, а пара (c3,c4)
находит последний.
Кроме того, для объединения с c3
фактически не требуется квантификатор c3.dateconn>=c.dateconn
(все, что ему нужно, это присоединиться к userid
), но это лишний бит сужает строки, к которым мы должны присоединиться.Это связано с тем, что, поскольку мы ищем самую последнюю (т.е. МАКСИМАЛЬНУЮ) дату в таблицах (c3,c4)
, а c
содержит дату MIN, нам нужно только смотреть на строки, для которых максимальная дата>> = минимальная дата.