Я отслеживаю просмотры на разных страницах и хочу знать наибольшую страницу за сеанс, чтобы узнать, как далеко они нажали (им необходимо просматривать каждую страницу до конца) в любой сессии.
Заказ перед группировкой - очень ненадежный способ сделать это.
MySQL
расширяет синтаксис GROUP BY
: вы можете использовать несгруппированные и неагрегированные поля в предложениях SELECT
и ORDER BY
.
В этом случае случайное значение page
выводится для каждого session
.
Документация прямо заявляет, что вы никогда не должны делать никаких предположений относительно того, какое именно значение это будет:
Не используйте эту функцию, если столбцы, которые вы пропускаете в части GROUP BY
, не являются постоянными в группе. Сервер может свободно возвращать любое значение из группы, поэтому результаты являются неопределенными, если все значения не совпадают.
Однако на практике возвращаются значения из первой отсканированной строки.
Так как вы используете ORDER BY page DESC
в своем подзапросе, эта строка является строкой с максимальным page
на сеанс.
Вы не должны полагаться на это, так как это поведение недокументировано, и если в следующей версии будет возвращена какая-то другая строка, это не будет считаться ошибкой.
Но вам даже не нужно делать такие неприятные трюки.
Просто используйте агрегатные функции:
SELECT MAX(page)
FROM views
WHERE user_id = '1'
GROUP BY
session
Это документированный и чистый способ сделать то, что вы хотите.
Создайте составной индекс на (user_id, session, page)
, чтобы запрос выполнялся быстрее.
Если вам нужны все столбцы из вашей таблицы, а не только агрегированные, используйте следующий синтаксис:
SELECT v.*
FROM (
SELECT DISTINCT user_id, session
FROM views
) vo
JOIN views v
ON v.id =
(
SELECT id
FROM views vi
WHERE vi.user_id = vo.user_id
AND vi.session = vo.session
ORDER BY
page DESC
LIMIT 1
)
Предполагается, что id
- это PRIMARY KEY
на views
.