MySQL Query GROUP BY день / месяц / год

457

Возможно ли, что я делаю простой запрос, чтобы подсчитать, сколько записей у меня есть за определенный период времени, например год, месяц или день, с полем TIMESTAMP, например:

SELECT COUNT(id)
FROM stats
WHERE record_date.YEAR = 2009
GROUP BY record_date.YEAR

Или даже:

SELECT COUNT(id)
FROM stats
GROUP BY record_date.YEAR, record_date.MONTH

Чтобы получить ежемесячную статистику.

Спасибо!

  • 1
    Я предполагаю, что это будет GROUP BY record_date.MONTH в вашем первом фрагменте кода?
Теги:
datetime
date
group-by

13 ответов

798
Лучший ответ
GROUP BY YEAR(record_date), MONTH(record_date)

Просмотрите функции даты и времени в MySQL.

  • 22
    Возможно, вы захотите добавить дополнительный столбец для большей ясности в некоторых случаях, например, когда записи охватывают несколько лет. SELECT COUNT (event_id), DATE_FORMAT (event_start, "% Y /% m")
  • 0
    Простой полный пример: SELECT count(*), record_date FROM anytable WHERE anytable.anycolumn = 'anycondition' GROUP BY YEAR(record_date), month(record_date); примечание: record_date является типом даты TIMESTAMP
Показать ещё 2 комментария
155
GROUP BY DATE_FORMAT(record_date, '%Y%m')

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

  • 1
    У меня есть ощущение, что это не будет работать хорошо, потому что функция форматирования не сможет использовать индекс в столбце даты.
  • 0
    @Stv: Вы можете рассмотреть ответ @ фу-чи тогда. Насколько я могу судить, групповые выражения как в этом ответе, так и в моем ответе оцениваются одинаково, но EXTRACT() может быть более эффективным, чем DATE_FORMAT() . (У меня нет MySQL для надлежащего тестирования, хотя.)
37

Я попытался использовать вышеприведенное выражение "WHERE", я подумал, что это правильно, поскольку никто не исправил его, но я ошибся; после некоторых поисков я выяснил, что это правильная формула для оператора WHERE, поэтому код будет выглядеть следующим образом:

SELECT COUNT(id)  
FROM stats  
WHERE YEAR(record_date) = 2009  
GROUP BY MONTH(record_date)
30

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

SELECT COUNT(id)
FROM stats
GROUP BY EXTRACT(YEAR_MONTH FROM record_date)

EXTRACT (unit FROM date) лучше, поскольку используется меньшая группировка, и функция возвращает числовое значение.

Условие сравнения при группировке будет быстрее, чем функция DATE_FORMAT (которая возвращает строковое значение). Попробуйте использовать поле function |, возвращающее нестроковое значение для условия сравнения SQL (WHERE, HAVING, ORDER BY, GROUP BY).

18

Если ваш поиск длится несколько лет, и вы все еще хотите ежемесячно собираться в группу, я предлагаю:

версия # 1:

SELECT SQL_NO_CACHE YEAR(record_date), MONTH(record_date), COUNT(*)
FROM stats
GROUP BY DATE_FORMAT(record_date, '%Y%m')

версия # 2 (более эффективная) :

SELECT SQL_NO_CACHE YEAR(record_date), MONTH(record_date), COUNT(*)
FROM stats
GROUP BY YEAR(record_date)*100 + MONTH(record_date)

Я сравнил эти версии с большой таблицей с 1 357 918 строками (), и вторая версия, по-видимому, имеет лучшие результаты.

версия1 (в среднем 10 выполняются): 1,404 секунды
версия2 (в среднем 10 выполняется): 0.780 секунд

Клавиша

(SQL_NO_CACHE добавлена ​​для предотвращения MySQL от CACHING к запросам.)

  • 1
    Подумайте о включении предложения @ fu-chi в ваши тесты, оно может оказаться еще более эффективным. Кроме того, вы тестировали GROUP BY YEAR(record_date)*100 + MONTH(record_date) , но почему бы не проверить GROUP BY YEAR(record_date), MONTH(record_date) ?
  • 2
    Если вы используете COUNT (1) с гарантированным COUNT (*), это будет еще быстрее, и данные результатов будут такими же.
Показать ещё 2 комментария
14

Если вы хотите группировать по дате в MySQL, используйте следующий код:

 SELECT COUNT(id)
 FROM stats
 GROUP BY DAYOFMONTH(record_date)

Надеюсь, это избавит некоторое время от тех, кто собирается найти этот поток.

  • 6
    Важно отметить, что вам также необходимо сгруппировать по MONTH(record_date) чтобы учесть несколько месяцев.
8

Если вы хотите отфильтровать записи за определенный год (например, 2000), тогда оптимизируйте предложение WHERE следующим образом:

SELECT MONTH(date_column), COUNT(*)
FROM date_table
WHERE date_column >= '2000-01-01' AND date_column < '2001-01-01'
GROUP BY MONTH(date_column)
-- average 0.016 sec.

Вместо:

WHERE YEAR(date_column) = 2000
-- average 0.132 sec.

Результаты были сгенерированы против таблицы, содержащей строки 300k и индекс в столбце даты.

Что касается предложения GROUP BY, я проверил три варианта против вышеупомянутой таблицы; вот результаты:

SELECT YEAR(date_column), MONTH(date_column), COUNT(*)
FROM date_table
GROUP BY YEAR(date_column), MONTH(date_column)
-- codelogic
-- average 0.250 sec.

SELECT YEAR(date_column), MONTH(date_column), COUNT(*)
FROM date_table
GROUP BY DATE_FORMAT(date_column, '%Y%m')
-- Andriy M
-- average 0.468 sec.

SELECT YEAR(date_column), MONTH(date_column), COUNT(*)
FROM date_table
GROUP BY EXTRACT(YEAR_MONTH FROM date_column)
-- fu-chi
-- average 0.203 sec.

Последний победитель.

6

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

SELECT count(id),
      YEAR(record_date),
      MONTH(record_date) 
FROM `table` 
GROUP BY YEAR(record_date),
        MONTH(record_date) 
ORDER BY YEAR(record_date) DESC,
        MONTH(record_date) DESC
4

Следующий запрос работал у меня в Oracle Database 12c Release 12.1.0.1.0

SELECT COUNT(*)
FROM stats
GROUP BY 
extract(MONTH FROM TIMESTAMP),
extract(MONTH FROM TIMESTAMP),
extract(YEAR  FROM TIMESTAMP);
2

Вы можете сделать это просто Mysql DATE_FORMAT() в GROUP BY. Возможно, вы захотите добавить дополнительный столбец для большей ясности в некоторых случаях, например, когда записи охватывают несколько лет, затем тот же месяц происходит в разные годы. Есть так много вариантов, которые вы можете настроить. Пожалуйста, прочитайте это для начала. Надеюсь, это будет очень полезно для вас. Вот пример запроса для вашего понимания

SELECT
    COUNT(id),
    DATE_FORMAT(record_date, '%Y-%m-%d') AS DAY,
    DATE_FORMAT(record_date, '%Y-%m') AS MONTH,
    DATE_FORMAT(record_date, '%Y') AS YEAR,

FROM
    stats
WHERE
    YEAR = 2009
GROUP BY
    DATE_FORMAT(record_date, '%Y-%m-%d ');
1

Я предпочитаю оптимизировать выбор группы за один год следующим образом:

SELECT COUNT(*)
  FROM stats
 WHERE record_date >= :year 
   AND record_date <  :year + INTERVAL 1 YEAR;

Таким образом вы можете просто привязать год один раз, например. '2009' с именованным параметром и не нужно беспокоиться о добавлении '-01-01' или передаче в '2010' отдельно.

Кроме того, поскольку предположим, что мы просто подсчитываем строки и id никогда не NULL, я предпочитаю COUNT(*) - COUNT(id).

0

Полное и простое решение с аналогичной производительностью, но более короткой и более гибкой альтернативой, действующей в настоящее время:

SELECT COUNT(*) FROM stats
-- GROUP BY YEAR(record_date), MONTH(record_date), DAYOFMONTH(record_date)
GROUP BY DATE_FORMAT(record_date, '%Y-%m-%d')
-3

.... group by to_char(date, 'YYYY') → 1989

.... group by to_char(date,'MM') → 05

.... group by to_char(date,'DD') --- > 23

.... group by to_char(date,'MON') --- > MAY

.... group by to_char(date,'YY') --- > 89

  • 0
    Это было бы очень очень медленно.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню