Как корректно выбрать максимальное значение за определенный период и получить соответствующий timestamp этого значения, чтобы избежать ошибки sql_mode=only_full_group_by?

Здравствуйте. У меня есть база данных MySQL версии <b>8.3.0</b> с такой структурой: <br/> <pre><code>id - int [AI]
player_count - int
timestamp - timestamp [CURRENT_TIMESTAMP, on update]</code></pre> <br/> Каждые 30 минут добавляется новая строка с актуальным значением <b>player_count</b> и <b>timestamp</b>. <br/> <br/> Мне нужно сделать выборку максимального значения <b>player_count</b> за определённый период, например, за месяц, и получить не только это значение, но и соответствующий <b>timestamp</b>. <br/> <br/> Затем я планирую объединить полученные результаты и отобразить график с максимальными значениями за неделю/месяц на протяжении более длительного времени (например, месяц, полгода, год и т.д.). <br/> <pre><code class="sql">SELECT MAX(player_count) AS players_max, `timestamp` FROM steam_stats WHERE MONTH(`timestamp`) = 7 AND YEAR(`timestamp`) = 2024</code></pre> <br/> Однако, при выполнении этого запроса возникает ошибка: <br/> <pre><code>1140 - In aggregated query without GROUP BY, expression #2 of SELECT list contains nonaggregated column 'db.steam_stats.timestamp'; this is incompatible with sql_mode=only_full_group_by</code></pre> <br/> Если я исключаю <b>`timestamp`</b> из SELECT, то получаю нужное значение, но не знаю, какому <b>timestamp</b> оно соответствует. <br/> <br/> Как правильно сформулировать SELECT и использовать GROUP BY, чтобы не отключать режим <b>sql_mode=only_full_group_by</b>?
  • 3 октября 2024 г. 16:44
Ответы на вопрос 3
Чтобы правильно выбрать максимальное значение `player_count` за определённый период и получить соответствующий `timestamp`, необходимо использовать подзапрос. Это поможет избежать ошибки, связанной с режимом `sql_mode=only_full_group_by`. В данном случае мы можем сначала найти максимальное значение и его `timestamp` в подзапросе, а затем использовать полученные результаты в основном запросе.

Вот пример SQL-запроса, который осуществляет это:

```sql
SELECT 
    player_count AS players_max,
    timestamp 
FROM 
    steam_stats 
WHERE 
    timestamp = (
        SELECT 
            timestamp 
        FROM 
            steam_stats 
        WHERE 
            MONTH(timestamp) = 7 AND YEAR(timestamp) = 2024 
        ORDER BY 
            player_count DESC 
        LIMIT 1
    );
```

### Разбор запроса:

1. **Внутренний подзапрос**: 
   - Он сначала выбирает `timestamp` из таблицы `steam_stats`, где месяц равен 7 и год равен 2024. 
   - Используя `ORDER BY player_count DESC LIMIT 1`, мы получаем `timestamp` максимального значения `player_count`.

2. **Внешний запрос**: 
   - Здесь мы выбираем `player_count` и `timestamp` из таблицы `steam_stats`, который соответствует найденному `timestamp` в подзапросе.

Таким образом, вы получите максимальное значение `player_count` и его соответствующий `timestamp` без нарушения правила `only_full_group_by`.
Ну типа так: 
SELECT DISTINCT
       MAX(player_count) OVER () AS players_max, 
       FIRST_VALUE(`timestamp`) OVER (ORDER BY player_count DESC) AS players_max_timestamp
FROM steam_stats 
WHERE `timestamp` >= '2024-07-01' AND `timestamp` < '2024-08-01'

Если максимальное значение player_count встречается более чем один раз, то будет выведен случайный timestamp из возможных. Если нужен определённый (например, самый последний из них), расширьте выражение сортировки в определении окна.
SELECT player_count, `timestamp`
  FROM steam_stats
  WHERE `timestamp` >= TIMESTAMP('2024-07-01')
    AND `timestamp` < TIMESTAMP('2024-08-01')
  ORDER BY player_count DESC
  LIMIT 1
Похожие вопросы