MySQLクエリGROUP BY日/月/年


649

次の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はあなたの最初のコードスニペットにあるはずだと思いますか?
チコドロ

回答:


1012
GROUP BY YEAR(record_date), MONTH(record_date)

MySQLの日付と時刻の関数を確認してください。


27
レコードが数年にわたる場合など、場合によっては、わかりやすくするために列を追加することもできます。SELECT COUNT(event_id)、DATE_FORMAT(event_start、 '%Y /%m')
Ric

単純な完全な例:SELECT count(*), record_date FROM anytable WHERE anytable.anycolumn = 'anycondition' GROUP BY YEAR(record_date), month(record_date);注:record_dateは日付型TIMESTAMPです
renedet '25

おそらく、これはMySQL 5.7でCOUNTエイリアス列を使用して実行されなかったことに言及する価値があります(エラーはなく、結果はゼロでした)。エイリアスを持つフィールドを選択するように変更した場合、エイリアスでグループ化できます。これは、ローカル環境で実行されている標準のMySQL 5.7 Dockerイメージであるため、なぜエラーが発生したり結果が返されなかったかはわかりません。
MrMesees 2017

3
ああ、神様、私がこれを以前に知っていたら... mysqlが1行で実行できる何かを実行するために、PHPの多くの行

230
GROUP BY DATE_FORMAT(record_date, '%Y%m')

(主に、潜在的な反対投票者に)注意してください。現在、これは他の提案ほど効率的ではないかもしれません。それでも、私はそれを代替手段として残し、他の解決策がどれほど高速であるかを確認するのに役立つ1つの方法も残しました。(違いを確認するまで、遅いことからすぐに判断することはできません。)また、時間が経過するにつれて、最適化に関してMySQLのエンジンに変更を加えて、このソリューションを作成することができます(おそらくそうではありません)。遠い点)将来的には、他のほとんどの効率とかなり同等になるでしょう。


3
フォーマット関数は日付列のインデックスを使用できないため、これはうまく機能しないと感じています。
Sonny、

@Stv:@ fu-chiの回答を検討することをお勧めします。私の知る限りでは、その回答と私の回答の両方のグループ化式は同じものに評価されEXTRACT()ますが、より効率的かもしれませんDATE_FORMAT()。(ただし、適切なテストのためのMySQLはありません。)
Andriy M

45

これを試して

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

EXTRACT(ユニットFROM日付)関数は、使用されるグループ化が少なく、関数が数値を返すため、より優れています。

グループ化時の比較条件は、DATE_FORMAT関数(文字列値を返す)より高速です。SQL比較条件(WHERE、HAVING、ORDER BY、GROUP BY)に文字列以外の値を返す関数|フィールドを使用してみてください。


43

上記の「WHERE」ステートメントを使用してみましたが、誰も修正していないので正しいと思いましたが、間違っていました。いくつか検索したところ、これがWHEREステートメントの正しい式であることがわかりましたので、コードは次のようになります。

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

30

検索が数年以上続いていて、それでも月ごとにグループ化したい場合は、次のことをお勧めします。

バージョン#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行の大きなテーブルでこれらのバージョンを比較しました()、2番目のバージョンの方がより良い結果が得られるようです。

バージョン1 (平均10回の実行):1.404秒
バージョン2 (平均10回の実行):0.780秒

SQL_NO_CACHEMySQLがクエリにキャッシュしないようにするために追加されたキー。)


1
テストに@ fu-chiの提案を含めることを検討してください。それがさらに効率的になる場合があります。また、をテストしましたがGROUP BY YEAR(record_date)*100 + MONTH(record_date)GROUP BY YEAR(record_date), MONTH(record_date)同様にテストしませんか?
Andriy M

2
COUNT(1)insteed COUNT(*)を使用すると、さらに高速になり、結果データは同じになります。
Pa0l0

2
それは何である*100バージョン#2には?前もって感謝します。
アビオン2018

1
*100YEAR(record_date)*100 + MONTH(record_date) == DATE_FORMAT(record_date, '%Y%m')
Phu Duy 2018

17

MySQLで日付でグループ化する場合は、以下のコードを使用します。

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

これがこのスレッドを見つけようとしている人たちの時間を節約することを願っています。


6
MONTH(record_date)複数の月を説明するためにグループ化する必要があることにも注意してください。
Webnet 2012年

14

特定の年(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.

結果は、30万行と日付列のインデックスを含むテーブルに対して生成されました。

用としてGROUP BY句、私は上記の表に対して3つのバリアントをテストしました。結果は次のとおりです。

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.

最後は勝者です。


10

現在アクティブでありながら、パフォーマンスがより低く、より柔軟な代替手段を備えた完全でシンプルなソリューション:

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

7

最新の月順に並べられた各年の月ごとの行数を含む月次統計を取得する場合は、次のようにしてください。

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

7

これは、GROUP BYのMysql DATE_FORMAT()関数で簡単に実行できます。レコードが数年にわたる場合や同じ月が別の年に発生する場合など、場合によっては、追加の列を追加してわかりやすくすることもできます。多くのオプションでこれをカスタマイズできます。はじめにお読みください。それがあなたにとって非常に役立つことを願っています。ここにあなたの理解のためのサンプルクエリがあります

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 ');

4

次のクエリは、Oracle Database 12cリリース12.1.0.1.0で機能しました。

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

2

私は次のように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

.... 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') ---> 5月

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


これは非常に遅くなります。
Earl3s 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.