SQLでカレンダーを取得する (WITH CTE) [SQLServer, MySQL]

SQLでカレンダーのデータを取得する方法を紹介します。
1か月の日付が7日ごとに改行して表示されるカレンダー形式のデータは、プログラムで作成するのも少し手間なので、SQLで取得する方法を覚えておくのもいいかもしれませんよ。

1か月のデータを取得する

カレンダーデータの取得の前に、まずは1か月分のデータの取得をします。
1か月のデータは月初めの日付(1日)~月終わりの日付(末日)の日付を取得します。
WHILEループやFETCHでカーソルを操作する方法が考えられますが、ここではWITH句を利用して再帰的にデータを取得します。

SQLServerでの取得

SQLServerで1か月分のデータを取得するSQLは次のようになります。
以下の例では2020年5月のデータを取得しています。

共通テーブル式のWITH句にまず開始のSELECT句を記載して開始日の日付を取得します。(18~19行目)
続けてUNIONで開始日~終了日の前日までの日付に1を加算するSELECT句を記述して日付を取得します。(20~26行目)
こうすることで再帰的に処理され、1か月分の日付を取得することができます。

取得結果
DATE_VALUE
2020-05-01
2020-05-02
2020-05-03
2020-05-04
2020-05-05
2020-05-06
2020-05-07
2020-05-08
2020-05-09
2020-05-10
2020-05-11
2020-05-12
2020-05-13
2020-05-14
2020-05-15
2020-05-16
2020-05-17
2020-05-18
2020-05-19
2020-05-20
2020-05-21
2020-05-22
2020-05-23
2020-05-24
2020-05-25
2020-05-26
2020-05-27
2020-05-28
2020-05-29
2020-05-30
2020-05-31

MySQLでの取得

MySQLで1か月分のデータを取得するSQLは次のようになります。

MySQLの場合もSQLServerの時とほぼ同じですが、MySQLのWITH句で再帰的に処理を行う場合はWITHの後に「RECURSIVE」が必要になります。(13行目)

カレンダーのデータを取得する

ここからが本題のカレンダーデータの取得です。
カレンダーのデータは単純に1か月分のデータではなく、第1週目には、1日になる前の前月の日付が含まれます。また、最終週には、週が終わるまで(土曜日まで)の翌月の日付が含まれます。ですので、第1週の開始日と最終週の終了日を取得してWITH句に指定します。

SQLServerでの取得

SQLServerでカレンダーデータを取得するSQLは次のようになります。

実行結果

SQLServerでのカレンダーデータの取得
データを取得するSQL(WITH句の後のSELECT句)では、WITH句で定義したDATE_TABLEからデータを取得する際に、CASE式で曜日番号ごとに横に展開します。(51~57行目)
展開した結果をサブクエリにしてMAX関数で最大値を取得することでWEEK_NO(週番号)ごとに1レコードになるようにします。(週番号が該当しない列の値はNULLになるのでMAX関数で最大値を取得することで有効な値のみ残り、結果として1行になります。)(38~44行目)

取得したデータを列に展開する方法については以下の記事も参考にしてください。

縦持ちのデータを横に展開する(CASE, IIF)[SQLServer, MySQL]
テーブルにレコードとして保存されているデータを取得する際に横に展開して1行にしたい場合があります。 例えば月ごとに登録されている金額データ...

MySQLでの取得

MySQLでカレンダーデータを取得するSQLは次のようになります。

実行結果

MySQLでのカレンダーデータの取得
MySQLでのカレンダーデータの取得もSQLServerの場合とほぼ同じです。
月の最終日の取得関数がEOMONTH関数からLAST_DAYになり、曜日の番号を取得する関数がDATEPART関数からDAYOFWEEK関数になります。
また、日付を加算するDATEADD関数がDATE_ADD関数になり、DATEDIFF関数では引数の日付が逆になります。