日付の計算とインターバル
期間の加算・減算と、日付間の差分計算を学びます。
「日付の計算とインターバル」はCoddyKit上の無料SQL Interview Prepレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSQL Interview Prep学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 SQL Interview Prepコースには全4レッスンが含まれています。
面接で日付計算が問われる理由
日付の算術演算は、SQLで最も実用的なスキルの1つです。そのため、面接ではアナリスト職やバックエンド職で頻繁に出題されます。ほぼすべてのビジネス上の問いには、過去30日間、週ごとの注文数、サインアップからの経過日数のように、時間の要素が含まれます。
注意すべき点は、日付関数がSQLの中で最も標準化されていない部分だということです。同じ処理でも、PostgreSQL、MySQL、SQL Serverでは構文が異なります。優れた候補者は、まず考え方を明確に説明し、その後で方言に合わせて構文を変えます。
- 期間を加算または減算する
- 2つの日付の差を計算する
INTERVAL値を扱う
INTERVAL型
PostgreSQLとSQL標準では、時間の期間はintervalという第一級の値です。日付またはタイムスタンプへの加算には、通常の+演算子と-演算子を使います。
これは「30日前」や「3か月後」を表現する最もすっきりした方法です。英語の文章のように読めるため、面接官にも好まれます。
SELECT
CURRENT_DATE,
CURRENT_DATE + INTERVAL '7 days' AS next_week,
CURRENT_DATE - INTERVAL '1 month' AS last_month,
NOW() + INTERVAL '90 minutes' AS soon;方言をまたいだ期間の加算
面接では、「MySQLとSQL Serverで7日を加算するにはどうしますか」とよく聞かれます。主要な3つの方言を知っていることは、実務経験の証になります。
- PostgreSQL:
d + INTERVAL '7 days' - MySQL:
DATE_ADD(d, INTERVAL 7 DAY) - SQL Server:
DATEADD(day, 7, d)
考え方は同じで、書き方だけが異なります。どの方言向けに書いているのかを、必ず明示してください。
-- MySQL
SELECT DATE_ADD(order_date, INTERVAL 7 DAY) AS due_date FROM orders;
-- SQL Server
SELECT DATEADD(day, 7, order_date) AS due_date FROM orders;2つの日付の差
日付の算術演算のもう一方の側面は、2つの日付がどれだけ離れているかを計算することです。結果は単位と方言によって異なります。
PostgreSQLでは、2つのdate値を減算すると、日数を表す整数が直接得られます。一方、2つのtimestamp値を減算すると、intervalが得られます。
-- Postgres: date - date returns an integer (days)
SELECT shipped_date - order_date AS days_to_ship
FROM orders;DATEDIFFとその落とし穴
DATEDIFFはMySQLとSQL Serverにありますが、動作が異なります。これは面接でよく使われるひっかけ問題です。
- MySQL:
DATEDIFF(end, start)は完全な日の数だけを返します。 - SQL Server:
DATEDIFF(unit, start, end)は単位を受け取り、完全に経過した単位ではなく境界をまたいだ回数を数えます。
この境界の扱いは重要です。SQL ServerのDATEDIFF(year, '2023-12-31', '2024-01-01')は、経過したのが1日だけであっても1を返します。
-- SQL Server: counts boundaries, not elapsed time
SELECT DATEDIFF(year, '2023-12-31', '2024-01-01'); -- 1
SELECT DATEDIFF(day, '2023-12-31', '2024-01-01'); -- 1正しい年齢の計算
「顧客の年齢を年単位で計算してください」は定番の問題です。うるう年があるため、日付の差を単純に365で割る方法ではずれが生じます。PostgreSQLにはAGE()があり、正確な暦上の期間を返します。
整数の年数をきれいに求めるには、年齢から年の部分を抽出します。
-- Postgres
SELECT
birth_date,
AGE(CURRENT_DATE, birth_date) AS exact_age,
EXTRACT(YEAR FROM AGE(CURRENT_DATE, birth_date)) AS age_years
FROM customers;実例:過去30日間の注文
ほぼすべての面接で使える定番のフィルタです。正しい方法は、日付列を関数でラップするのではなく、計算した基準日時刻と比較することです。
order_dateを固定の基準日時刻と比較すれば、order_dateに設定されたインデックスを利用できます。このインデックスの点については、後で改めて説明します。
SELECT COUNT(*) AS recent_orders
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '30 days';暦月には半開区間を使う
「2024年3月のすべての注文」と問われたとき、タイムスタンプ列に対してBETWEEN '2024-03-01' AND '2024-03-31'を使うのは避けてください。これでは3月31日の午後11時の行が漏れ、境界値のずれも起こりやすくなります。
堅牢なパターンは半開区間です。開始日時刻以上(>=)かつ翌月の開始日時刻未満(<)にします。どの列の精度でも機能します。
SELECT *
FROM orders
WHERE order_ts >= DATE '2024-03-01'
AND order_ts < DATE '2024-04-01';EXTRACTと日付の各要素
日付から単一の要素を取り出す処理は、レポート業務で頻繁に行います。標準的な関数はEXTRACT(part FROM d)で、PostgreSQLとMySQLが対応しています。
EXTRACT(YEAR FROM d)、MONTH、DAY- 曜日には
EXTRACT(DOW FROM d) - SQL Serverでは代わりに
DATEPART(weekday, d)を使います
注意:MONTHだけを抽出すると、異なる年の3月が同じグループにまとめられます。これは、ほとんどの場合、意図した結果ではありません。
SELECT
EXTRACT(YEAR FROM order_ts) AS yr,
EXTRACT(MONTH FROM order_ts) AS mo,
COUNT(*) AS n
FROM orders
GROUP BY 1, 2
ORDER BY 1, 2;詳しい例:次の誕生日までの日数
これは、抽出と加算を組み合わせた、より難しい算術演習です。誕生月と誕生日から今年の誕生日を作り、すでに過ぎている場合は翌年に繰り越します。
この処理を声に出して説明すれば、今年の誕生日がすでに過ぎている場合のような境界ケースについても、筋道立てて考えられることを面接官に示せます。
-- Postgres
SELECT
name,
CASE
WHEN MAKE_DATE(EXTRACT(YEAR FROM CURRENT_DATE)::int,
EXTRACT(MONTH FROM birth_date)::int,
EXTRACT(DAY FROM birth_date)::int) >= CURRENT_DATE
THEN MAKE_DATE(EXTRACT(YEAR FROM CURRENT_DATE)::int,
EXTRACT(MONTH FROM birth_date)::int,
EXTRACT(DAY FROM birth_date)::int) - CURRENT_DATE
ELSE MAKE_DATE(EXTRACT(YEAR FROM CURRENT_DATE)::int + 1,
EXTRACT(MONTH FROM birth_date)::int,
EXTRACT(DAY FROM birth_date)::int) - CURRENT_DATE
END AS days_until
FROM customers;月の初日と末日
「各注文の月の末日を求めてください」という問題では、組み込み機能を使うか、自分で作り直すかが試されます。PostgreSQLではDATE_TRUNCと期間の算術演算を組み合わせ、MySQLではLAST_DAY()を直接使えます。
Postgresで月末日を求めるコツは、月初に切り捨て、1か月を加算してから1日を減算することです。
-- Postgres
SELECT
DATE_TRUNC('month', order_ts) AS month_start,
DATE_TRUNC('month', order_ts) + INTERVAL '1 month - 1 day' AS month_end
FROM orders;
-- MySQL: LAST_DAY(order_ts)簡単な確認
方言による日付の差の動作について理解しているか確認しましょう。
まとめ:日付の算術演算とインターバル
面接で押さえておくべきポイントは次のとおりです。
- Postgresでは
INTERVAL値と+/-を使い、MySQLではDATE_ADD/DATEDIFF、SQL ServerではDATEADD/DATEDIFFを使います。 - SQL ServerのDATEDIFFは、経過した単位ではなく境界をまたいだ回数を数えます。ここが最大の落とし穴です。
- 年齢を年単位で求める場合は、日数を365で割るのではなく、
AGE()から年を抽出します。 - 最近の行をフィルタリングするときは、列を計算した基準日時刻と比較し、月単位の範囲には半開区間(
>= start AND < next)を使います。
まず概念を説明し、その後で方言に合わせて書き方を変えてください。
よくある質問
「日付の計算とインターバル」レッスンは無料ですか?
はい。「日付の計算とインターバル」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、SQL Interview Prepコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 SQL Interview Prepコースには全4レッスンが含まれています。
「日付の計算とインターバル」で何を学びますか?
期間の加算・減算と、日付間の差分計算を学びます。 ブラウザで直接実行するハンズオンコードでSQL Interview Prepを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
SQL Interview Prepを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのSQL Interview Prepは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「日付の計算とインターバル」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このSQL Interview Prepレッスンでコードを書いて実行できますか?
はい。すべてのSQL Interview Prepレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 日付の計算とインターバル
- 日付の切り捨てとバケット化
- 文字列の解析とフォーマット
- タイムゾーンとタイムスタンプ