コマンド道場

$ man generate-series

GENERATE_SERIES

行を作る関数

連番や日付の並びを行として作る。集計に出てこない月をゼロで埋めたいときに使う。

呼び出しの形

GENERATE_SERIES(開始, 終了)
GENERATE_SERIES(開始, 終了, 刻み)
GENERATE_SERIES(開始日, 終了日, INTERVAL '1 month')

つまずきやすいところ

  • 終わりの値を含みます。 GENERATE_SERIES(1, 5) は 5 行返ります。

  • 刻みの向きが範囲と逆だと、エラーにならず 0 行になります(GENERATE_SERIES(1, 5, -1) は 0 行)。刻みを 0 にしたときだけはエラーです。

  • 日付を渡すと timestamp が返ります。突き合わせる側も DATE_TRUNC などで同じ粒度にそろえないと、全部 0 のまま静かに間違います

  • 別名を付けないと、列名は generate_series になります。

実行例

結果は実際に流したものです。同じ SQL を 自由に打てる画面 で試すと、同じ結果になります。

連番を行として作る(刻みつき)
SELECT * FROM GENERATE_SERIES(1, 10, 3)
generate_series
1
4
7
10

4

10 も含みます。刻みが 3 なので 1・4・7・10 の 4 行です。

素直に集計すると、受注の無い月は消える
SELECT TO_CHAR(DATE_TRUNC('month', juchu_on), 'YYYY-MM') AS tsuki, COUNT(*) AS kensu FROM juchu GROUP BY 1 ORDER BY 1
tsukikensu
2025-112
2025-123
2026-012
2026-023

4

4 行しか出ません。2026-03 は 0 と出るのではなく、行ごと消えています。

月の並びを先に作れば、無い月も 0 で並ぶ
SELECT TO_CHAR(m, 'YYYY-MM') AS tsuki, COUNT(j.juchu_id) AS kensu FROM GENERATE_SERIES(DATE '2025-11-01', DATE '2026-03-01', INTERVAL '1 month') AS m LEFT JOIN juchu j ON DATE_TRUNC('month', j.juchu_on) = m GROUP BY m ORDER BY m
tsukikensu
2025-112
2025-123
2026-012
2026-023
2026-030

5

5 行になりました。2026-03 は受注が 1 件もありませんが、0 として残ります。

説明

GENERATE_SERIES は、値ではなく行を返す関数です。FROM に書いて、表と同じように使います。

よく使うのは「データが無い期間も表に出したい」ときです。受注を GROUP BY で月ごとに数えると、受注が 1 件も無い月は 0 が出るのではなく、行そのものが消えます。消えるのは 0 件の月だけなので、表を見ても「その月が抜けている」ことに気づきにくく、期間が詰まって見えます。月の並びを先に GENERATE_SERIES で作り、そこへ実績を外部結合すると、無い月が 0 として並びます。

⚠️ 終わりの値を含みます。 GENERATE_SERIES(1, 5) は 4 行ではなく 5 行です。終わりを含まない範囲に慣れていると 1 行ずれます。

日付で使うときは第 3 引数に INTERVAL を渡します。返るのは timestamp なので、突き合わせる側も DATE_TRUNC で同じ粒度にそろえてください。粒度がずれていると、エラーにはならず、どの行にも当たらないまま全部 0 になります

ほかの製品でも通るか

この書き方が使えない製品があります そのまま使える: PostgreSQL / SQLite / SQL Server

  • MySQL では使えませんGENERATE_SERIES(連番を行として作る)
  • MariaDB では使えませんGENERATE_SERIES(連番を行として作る)

未確認: Oracle Database / IBM Db2

製品ごとの対応表(根拠つき)を見る

次に読む

関係する関数

根拠にした一次情報