コマンド道場

日付関数(EXTRACT で年月を取り出す)の使い方

日付から、必要な部分だけを取り出す

shain社員

hired_on
2014-04-01
2016-10-01
2019-04-01
2020-04-01
2024-04-01
2018-04-01

EXTRACT で作った列を足す年を取り出した結果

hired_onnen
2014-04-012014
2016-10-012016
2019-04-012019
2020-04-012020
2024-04-012024
2018-04-012018

EXTRACT(YEAR FROM hired_on) AS nen

  • 青い列= 式から作った列。元の表には無い列です
  • 社員 18年を取り出した結果 18(行数は変わりません。減らすのは WHERE の仕事です)

行は 1 行も減っていません。日付を切り出して新しい列を作っているだけです。

日付から「年」や「月」だけを取り出すのが EXTRACT です。 年月ごとの集計はこれで書きます。ただし絞り込みに使うと索引が効かなくなるので、「まとめるときは EXTRACT、絞るときは範囲」と覚えてください。

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

  • SQLite では使えませんEXTRACT(日付の一部を取り出す)・DATE 'YYYY-MM-DD' の日付リテラル
  • SQL Server では使えませんEXTRACT(日付の一部を取り出す)・DATE 'YYYY-MM-DD' の日付リテラル
  • Oracle Database では使えませんDATE 'YYYY-MM-DD' の日付リテラル

未確認: IBM Db2

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

このページの実行結果と図は、すべて本物のデータベースに同じ SQL を流して得たものです。手で書いた「たぶんこうなる」ではありません。

01EXTRACT で年・月・日を取り出す

結論: EXTRACT(取り出す部分 FROM 日付) と書きます。返るのは数値です。

  • EXTRACT(YEAR FROM hired_on) … 年
  • EXTRACT(MONTH FROM hired_on) … 月
  • EXTRACT(DAY FROM hired_on) … 日

FROM が入る独特な書き方ですが、これが標準 SQL の形です。カンマ区切りではないので注意してください。

⚠️ この書き方は製品差が大きい部分です。 SQLite と SQL Server には EXTRACT がありません(それぞれ strftimeDATEPART を使います)。使えない製品がある例には自動で注記が出ます。

1 行ずつ、何をしているか
  1. SELECT EXTRACT(YEAR FROM hired_on) AS nen,日付から年を切り出す
  2. count(*) AS ninzuまとまりごとに数える
  3. FROM shainどの表を見るか
  4. GROUP BY EXTRACT(YEAR FROM hired_on)同じ年をひとまとめにする
  5. ORDER BY nen年の順に並べる

GROUP BY にも同じ式を書きます。SELECT で付けた別名を GROUP BY に書けるかは製品によって違うので、式をそのまま書くほうが確実です。

年と月を取り出す
SELECT name, hired_on,
       EXTRACT(YEAR FROM hired_on)  AS nen,
       EXTRACT(MONTH FROM hired_on) AS tsuki
FROM shain
ORDER BY shain_id;
namehired_onnentsuki
鈴木2014-04-0120144
佐藤2016-10-01201610
田中2019-04-0120194
中村2020-04-0120204
小林2024-04-0120244
加藤2018-04-0120184

18 … うち先頭 6 行を表示

日付はそのまま残しつつ、年と月の列が増えています。値は数値なので、そのまま計算や比較に使えます。

⚠️ この書き方は SQLite / SQL Server では使えません(EXTRACT(日付の一部を取り出す))。製品ごとの対応表

02年や月でまとめて数える

結論: GROUP BYEXTRACT の式を書けば、年ごと・月ごとの集計になります。

これが EXTRACT のいちばん多い使い道です。日付をそのまま GROUP BY に書くと 1 日ごとに分かれてしまうので、まとめたい粒度まで削ってからグループにします。

次の例は入社月の分布です。4 月に 13 人が集中していることが 1 目で分かります。生の日付を眺めていても気づけない偏りが、粒度を落とすと見えてきます。

年ごとの入社人数
SELECT EXTRACT(YEAR FROM hired_on) AS nen,
       count(*) AS ninzu
FROM shain
GROUP BY EXTRACT(YEAR FROM hired_on)
ORDER BY nen;
nenninzu
20131
20141
20151
20162
20171
20181
20191
20202
20211
20221
20231
20241
20251
20263

14

14 行です。1 人ずつの年が多いなか、2016 年と 2020 年が 2 人、2026 年が 3 人です。

⚠️ この書き方は SQLite / SQL Server では使えません(EXTRACT(日付の一部を取り出す))。製品ごとの対応表

月ごとの入社人数
SELECT EXTRACT(MONTH FROM hired_on) AS tsuki,
       count(*) AS ninzu
FROM shain
GROUP BY EXTRACT(MONTH FROM hired_on)
ORDER BY tsuki;
tsukininzu
413
51
61
103

4

4 行しかありません。18 人のうち 13 人が 4 月入社で、あとは 5 月・6 月・10 月だけです。

⚠️ この書き方は SQLite / SQL Server では使えません(EXTRACT(日付の一部を取り出す))。製品ごとの対応表

03⚠️ よくある間違い:絞り込みに EXTRACT を使わない

結論: 「2026 年に入社した人」を WHERE EXTRACT(YEAR FROM hired_on) = 2026 と書かないでください。 結果は正しいのに、遅くなります。

理由は、列を関数で包むと、その列の索引が使えなくなるからです。索引は hired_on の値そのものに対して作られているので、「hired_on を加工した結果」で探すことはできません。表の全行を 1 つずつ計算して確かめることになります。

18 行なら一瞬ですが、100 万行なら体感で分かるほど変わります。

同じ結果を範囲で書けます。 こちらは hired_on をそのまま比べているので索引が使えます。

  • WHERE EXTRACT(YEAR FROM hired_on) = 2026
  • WHERE hired_on >= DATE '2026-01-01' AND hired_on < DATE '2027-01-01'

⚠️ 上限は翌年の 1 月 1 日未満にします。<= DATE '2026-12-31' にすると、列が時刻を持つ型のときに大晦日ぶんが落ちます。

✗ 列を関数で包む書き方
SELECT count(*) AS n
FROM shain
WHERE EXTRACT(YEAR FROM hired_on) = 2026;
n
3

1

3 人と正しく出ます。結果は間違っていませんが、この形では索引をたどれません。

⚠️ この書き方は SQLite / SQL Server では使えません(EXTRACT(日付の一部を取り出す))。製品ごとの対応表

○ 範囲で書く(結果は同じ 3 人)
SELECT count(*) AS n
FROM shain
WHERE hired_on >= DATE '2026-01-01'
  AND hired_on <  DATE '2027-01-01';
n
3

1

同じ 3 人です。hired_on をそのまま比べているので、索引がある表では絞り込みに使えます。

⚠️ この書き方は SQLite / SQL Server / Oracle Database では使えません(DATE 'YYYY-MM-DD' の日付リテラル)。製品ごとの対応表

04日付の書き方は型を明示する

結論: 日付を書くときは DATE '2026-01-01' の形が標準です。

単なる文字列 '2026-01-01' でも多くの製品では自動で日付に直されて通ります。しかし書式の解釈は設定で変わります'01/02/2026' が 1 月 2 日なのか 2 月 1 日なのかは、環境しだいです。

DATE を前に置いて型を明示しておけば、読む人にも機械にも意図が伝わります。年月日は必ず 4 桁の年から書くYYYY-MM-DD)のも同じ理由です。

⚠️ この書き方も製品差があります。SQLite と SQL Server には DATE 'YYYY-MM-DD' という形がありません。それぞれ文字列として書きます。

日付リテラルで比べる
SELECT name, hired_on
FROM shain
WHERE hired_on >= DATE '2025-01-01'
ORDER BY hired_on;
namehired_on
松本2025-04-01
木村2026-04-01
渡辺2026-05-01
大野2026-06-01

4

4 人です。日付は数と同じように大小を比べられます。

⚠️ この書き方は SQLite / SQL Server / Oracle Database では使えません(DATE 'YYYY-MM-DD' の日付リテラル)。製品ごとの対応表

05このページで扱っていないこと

結論: 日付の計算(引き算・加算)と「今日」の取得は、製品差がとても大きい部分です。

  • 2 つの日付の差 … PostgreSQL は引き算で日数が出ますが、SQL Server や MySQL は DATEDIFF を使い、引数の順序も戻り値の単位も違います
  • 何日後・何か月後 … INTERVALDATEADDDATE_ADD と書き方が分かれます
  • 今日の日付 … CURRENT_DATEGETDATE()SYSDATE などがあります

このサイトでは構文ごとに実際の対応を調べて注記を出す方式をとっており、これらはまだ対応表に載せていません。根拠を示せない注記は出さない方針なので、ここでは扱わずに練習問題側で個別に説明しています。

⚠️ また、「今日」を使う例はこのページには載せられません。実行結果は事前に生成して保存しているため、日によって答えが変わる式を載せると、書いてある結果と自分で打った結果が食い違うからです。

退職者だけを取り出す(差の計算は練習問題で)
SELECT name, hired_on, taishoku_on
FROM shain
WHERE taishoku_on IS NOT NULL
ORDER BY shain_id;
namehired_ontaishoku_on
高橋2021-04-012025-09-30
山本2016-04-012024-03-31

2

2 人です。この 2 人の在籍日数を出す書き方は、製品によって変わります。練習問題「2 つの日付の差を出す」で扱っています。

自分で打ってみる

このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。

押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。

解いてみる

読んだだけでは書けるようになりません。実行結果で採点します。

ここで出てくる関数を引く

関連するトピック

根拠(一次情報)