Как группировать по неделям в MySQL? - PullRequest
72 голосов
/ 15 ноября 2009

Сервер таблиц Oracle предлагает встроенную функцию, TRUNC(timestamp,'DY'). Эта функция преобразует любую метку времени в полночь предыдущего воскресенья. Какой лучший способ сделать это в MySQL?

Oracle также предлагает TRUNC(timestamp,'MM') для преобразования метки времени в полночь первого дня месяца, в котором она произошла. В MySQL это просто:

TIMESTAMP(DATE_FORMAT(timestamp, '%Y-%m-01'))

Но этот DATE_FORMAT трюк не будет работать неделями. Мне известна функция WEEK(timestamp), но я действительно не хочу номер недели в году; этот материал для многолетней работы.

Ответы [ 6 ]

98 голосов
/ 15 ноября 2009

Вы можете использовать как YEAR(timestamp), так и WEEK(timestamp), и использовать оба эти выражения в выражениях SELECT и GROUP BY.

Не слишком элегантно, но функционально ...

И, конечно, вы можете объединить эти две части даты в одном выражении, то есть что-то вроде

SELECT CONCAT(YEAR(timestamp), '/', WEEK(timestamp)), etc...
FROM ...
WHERE ..
GROUP BY CONCAT(YEAR(timestamp), '/', WEEK(timestamp))

Редактировать : Как отмечает Мартин ХХ, вы также можете использовать функцию YEARWEEK(mysqldatefield), хотя ее вывод не так удобен для глаз, как более длинная формула выше.

Редактировать 2 [3 с половиной года спустя!]:
YEARWEEK(mysqldatefield) с необязательным вторым аргументом (mode), установленным в 0 или 2, вероятно, является наилучшим способом агрегирования по полным неделям (т. Е. Включая недели, которые колеблются после 1 января), если это что желательно. Подход YEAR() / WEEK(), первоначально предложенный в этом ответе, позволяет разделить агрегированные данные для таких "колеблющихся" недель на две части: одну с предыдущим годом, одну с новым годом.
Ежегодно необходимо проводить чистую обработку каждый год за счет наличия до двух неполных недель, по одной на каждом конце, что часто необходимо для учета и т. Д., И для этого подход YEAR() / WEEK() лучше.

25 голосов
/ 01 августа 2012

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

2012/1
2012/10
2012/11
...
2012/19
2012/2

Вот мое решение для подсчета и группировки по неделям:

SELECT CONCAT(YEAR(date), '/', WEEK(date)) AS week_name, 
       YEAR(date), WEEK(date), COUNT(*)
FROM column_name
GROUP BY week_name
ORDER BY YEAR(DATE) ASC, WEEK(date) ASC

Формирует:

YEAR/WEEK   YEAR   WEEK   COUNT
2011/51     2011    51      15
2011/52     2011    52      14
2012/1      2012    1       20
2012/2      2012    2       14
2012/3      2012    3       19
2012/4      2012    4       19
24 голосов
/ 15 ноября 2009

Разобрался ... это немного громоздко, но вот оно.

FROM_DAYS(TO_DAYS(TIMESTAMP) -MOD(TO_DAYS(TIMESTAMP) -1, 7))

И, если ваши бизнес-правила говорят, что ваши недели начинаются по понедельникам, измените значение -1 на -2.


Редактировать

Прошли годы, и я наконец-то нашел время написать это. http://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/

21 голосов
/ 15 ноября 2009

Вы можете получить объединенный год и номер недели (200945), используя функцию YEARWEEK () . Если я правильно понимаю вашу цель, это позволит вам сгруппировать многолетние данные.

Если вам нужна фактическая временная метка для начала недели, это менее приятно:

DATE_SUB( field, INTERVAL DAYOFWEEK( field ) - 1 DAY )

Для ежемесячного заказа вы можете рассмотреть функцию LAST_DAY () - сортировка будет выполняться по последнему дню месяца, но это должно быть эквивалентно сортировке по первому дню месяца ... shouldn ' не так ли?

4 голосов
/ 31 августа 2010

Просто укажите это в списке:

DATE_FORMAT($yourDate, \'%X %V\') as week

А

group_by(week);
2 голосов
/ 18 января 2011

Если вам нужна дата «окончания недели», это также сработает. Это будет подсчитывать количество записей за каждую неделю. Пример: если три рабочих задания были созданы между (включительно) 1/2/2010 и 1/8/2010 и 5 были созданы между (включительно) 1/9/2010 и 16.01.2010, получится:

3 1/8/2010
5 1/16/2010

Мне пришлось использовать дополнительную функцию DATE () для усечения моего поля даты и времени.

SELECT COUNT(*), DATE_ADD( DATE(wo.date_created), INTERVAL (7 - DAYOFWEEK( wo.date_created )) DAY) week_ending FROM work_order wo GROUP BY week_ending;

...