Як згрупувати за тижнями в MySQL?


91

Сервер таблиць Oracle пропонує вбудовану функцію, TRUNC(timestamp,'DY') . Ця функція перетворює будь-яку позначку часу на північ попередньої неділі. Який найкращий спосіб це зробити в MySQL?

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

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

Але ця DATE_FORMATхитрість не спрацює тижнями. Мені відома WEEK(timestamp)функція, але я справді не хочу номер тижня протягом року; цей матеріал призначений для багаторічної роботи.


ви маєте на увазі trunc (sysdate, 'W'), а не trunc (sysdate, 'DY')
Девід Олдрідж

TRUNC(date, 'DY' )отримує тижні з недільного початку. 'W'отримує початок з понеділка, принаймні в моїй системі.
O. Jones

Відповіді:


123

Ви можете використовувати обидва 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 1/2 роки пізніше!]:
YEARWEEK(mysqldatefield)З необов’язковим другим аргументом ( mode), встановленим на 0 або 2, є, мабуть, найкращим способом агрегування за повними тижнями (тобто, включаючи тижні, які страждають від 1 січня), якщо це так що бажано. YEAR() / WEEK()Підхід спочатку запропонований в цій відповіді є ефект розщеплення агрегованих даних для такого «ТРАНСЗОНАЛЬНИЙ» тижні в два: один з колишнім роком, один з новим роком.
Щороку в бухгалтерському обліку тощо бажаний чіткий зріз щороку, за рахунок наявності до двох неповних тижнів, по одному в кожному кінці, і для цього YEAR() / WEEK()підхід кращий.


12
YEARWEEK()призводить до того, INT(6)що, на мою думку, буде швидше сортувати / приєднуватися / групуватися
KCD

@mjv: що трапляється, коли два роки ділять один тиждень? як для цього 31-12-2012 До 6-1-2013 (з понеділка до сонця). чи є якесь рішення цього?
hardik

@hardik: див. Редагування 2. Залежно від власних потреб, РІК () може бути кращим ключем для агрегування, якщо хтось воліє працювати з повними тижнями, а не розділяти останній / перший частковий тиждень року.
mjv

@mjv ось ще одне рішення для цього посилання
hardik

переконайтесь, що "мітка часу" не є цілим числом, як це було в моїй таблиці. WEEK (відмітка часу) приймає тип стовпця дати / відмітки часу як дійсний аргумент
Усман Шаукат

37

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

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

4
замовлення за датою ( ORDER BY date ASC) теж повинно зробити трюк
Fender

36

Зрозумів ... це трохи громіздко, але ось воно.

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

І якщо у правилах вашого бізнесу сказано, що ваші тижні починаються з понеділка, змініть -1на -2.


Редагувати

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


@Ollie - я б подумав про використання DAYOFWEEK () або WEEKDAY () для полегшення читабельності.
martin clayton

1
Мартіне, я розглянув це і виявив, що ці функції працюють 0-6 для понеділка-неділі. Правила мого бізнесу стверджують, що тижні починаються в неділю о 00:00, тому вихідні дні стали трохи потворними. Ви маєте рацію щодо читабельності.
О. Джонс,

@OllieJones ідеально! Дуже дякую!
Джо Ченг,

1
Чудове рішення та стаття. Дякую!
Джеремі Віггінс

Є спосіб встановити "понеділок" першим днем?
Педро Хоакін

25

Ви можете отримати зв’язаний номер року та тижня (200945) за допомогою функції YEARWEEK () . Якщо я правильно розумію вашу мету, це повинно дозволити вам згрупувати ваші багаторічні дані.

Якщо вам потрібна фактична позначка часу для початку тижня, це буде менш приємно:

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

Для щомісячного замовлення ви можете розглянути функцію LAST_DAY () - сортування відбуватиметься за останнім днем ​​місяця, але це має бути еквівалентно сортуванню за першим днем ​​місяця ... чи не так?


1
+1 Мартін. Дух для мене, я забув про РІК () ... Я просто не дуже ним користуюся.
mjv


2

Якщо вам потрібна дата "закінчення тижня", це також буде працювати. Це буде враховувати кількість записів за кожен тиждень. Приклад: Якби три робочі замовлення були створені між (включно) 1/2/2010 і 8.01.2010, а 5 було створено між (включно) 9.01.2010 і 16.01.2010, це поверне:

3 8.01.2010
5 16.01.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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.