MySQLで週ごとにグループ化する方法は?


92

Oracleのテーブルサーバーは、組み込み関数を提供しますTRUNC(timestamp,'DY')。この関数は、タイムスタンプを前の日曜日の深夜に変換します。MySQLでこれを行うための最良の方法は何ですか?

オラクルはTRUNC(timestamp,'MM')、タイムスタンプが発生した月の初日の深夜にタイムスタンプを変換することも提供しています。MySQLでは、これは簡単です。

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

しかし、このDATE_FORMATトリックは数週間は機能しません。私はそのWEEK(timestamp)機能を知っていますが、1年以内の週番号は本当に必要ありません。これは複数年の作業用です。


trunc(sysdate、 'DY')ではなくtrunc(sysdate、 'W')を意味します
David Aldridge

TRUNC(date, 'DY' )日曜日の開始で数週間を取得します。'W'少なくとも私のシステムでは、月曜日に開始されます。
O.ジョーンズ

回答:


123

YEAR(timestamp)との両方を使用できWEEK(timestamp)SELECTGROUP BY句でこれらの式の両方を使用できます。

過度にエレガントではありませんが、機能的です...

そしてもちろん、これら2つの日付部分を1つの式に組み合わせることができます。

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

編集:マーティンが指摘しているように、このYEARWEEK(mysqldatefield)関数を使用することもできますが、その出力は上記の長い式ほど見やすくはありません。


編集2 [3年半後!]:
YEARWEEK(mysqldatefield)オプションの2番目の引数(mode)を0または2に設定すると、完全な週(つまり、1月1日にまたがる週を含む)で集計するのにおそらく最良の方法です。何が望まれるか。YEAR() / WEEK()当初、この回答で提案されたアプローチは、そのようなのために分割集計データの効果がある「またぐ」元年と1、新しい年と1:2で週間。
会計などでは、最大2週間(両端に1週間ずつ)の費用がかかる毎年のクリーンカットが望まれることが多く、そのためのYEAR() / WEEK()アプローチの方が優れています。


12
YEARWEEK()結果として、INT(6)ソート/参加/グループ化がより高速になると私は信じています
KCD 2012年

@mjv:2年が同じ週を共有するとどうなりますか?このように31-12-2012から6-1-2013(月曜日から日曜日)。これに対する解決策はありますか?
hardik 2013

@hardik:編集2を参照してください。年の最後/最初の部分的な週を分割するのではなく、完全な週で作業する場合は、ニーズに応じてYEARWEEK()を集計する方がよい場合があります。
mjv 2013

@mjvここにそのリンク
hardik 2013

「タイムスタンプ」が、テーブルにあるような整数ではないことを確認してください。WEEK(timestamp)は、有効な引数として日付/タイムスタンプ列タイプを取ります
Usman Shaukat 2015

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)で注文することもうまくいくはずです
フェンダー

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()の使用を検討したいと思います。
マーティンクレイトン

1
マーティン、私はそれを考慮し、それらの関数が月曜日から日曜日に0から6で実行されることを発見しました。私のビジネスルールでは、週は日曜日の00:00に始まると言われているので、WEEKDAYのものは少し醜いものになりました。あなたは読みやすさについて正しいです。
O.ジョーンズ

@OllieJones完璧!どうもありがとうございます!
ジョーチェン

1
素晴らしいソリューションと記事。ありがとうございました!
ジェレミーウィギンズ2014年

「月曜日」を最初の日として設定する方法はありますか?
ペドロホアキン

25

YEARWEEK()関数を使用して、連結された年と週の番号(200945)を取得できます。私があなたの目標を正しく理解していれば、それはあなたがあなたの複数年のデータをグループ化することを可能にするはずです。

週の初めの実際のタイムスタンプが必要な場合は、あまり良くありません。

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

月次の順序付けの場合、LAST_DAY()関数を検討することができます-並べ替えは月の最終日で行われますが、それは月の最初の日で並べ替えるのと同じである必要があります...そうではありませんか?


1
+1マーティン。YEARWEEK()を忘れてしまいました...あまり使用していません。
mjv 2009年

4

選択でこれを広告するだけです:

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

そして

group_by(week);

ごと

データを継続的に取得するのではなく、特定の1つの日付
Chique_Code

2

「週末」の日付が必要な場合は、これも機能します。これにより、各週のレコード数がカウントされます。例:2010年1月2日から2010年1月8日までの間に3つの作業指示書が作成され、2010年1月9日から2010年1月16日までの間に5つの作業指示書が作成された場合、次のようになります。

3 2010年1月8日
5

日時フィールドを切り捨てるには、追加の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;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.