$ 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| tsuki | kensu |
|---|---|
| 2025-11 | 2 |
| 2025-12 | 3 |
| 2026-01 | 2 |
| 2026-02 | 3 |
4 行
4 行しか出ません。2026-03 は 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| tsuki | kensu |
|---|---|
| 2025-11 | 2 |
| 2025-12 | 3 |
| 2026-01 | 2 |
| 2026-02 | 3 |
| 2026-03 | 0 |
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
次に読む
根拠にした一次情報
- PostgreSQL 18 マニュアル: 集合を返す関数(2026-09-04 確認)