SQLで日付を加算・減算する構文は、データベース製品ごとに異なります。この記事ではSQL Server 2022(16.x)とMySQL 8.4を対象に、日数・月数・年数の計算、月末、年齢、期間抽出を解説します。構文の比較とタイムゾーンの補足にはPostgreSQL 17を使います。各コードの製品名を確認し、別製品の構文を混在させないでください。
例は既存テーブルを変更しない参照クエリです。掲載結果は公式仕様に基づく期待値で、ここでのDBMS実機実行結果ではありません。日付だけを扱う例は型を明示し、日時を扱う例は時刻と精度にも注意します。
SQLでの日付加算の基本構文
SQL ServerではDATEADD、MySQLではDATE_ADDやINTERVAL式を使います。「SQLなら同じ式が使える」というわけではありません。
DATEADD関数の基本構文
SQL Server 2022のDATEADD関数で日付に期間を加算します。以下の日本語の引数名は説明用で、そのまま実行するSQLではありません。
-- SQL Server 2022:説明用の構文(そのまま実行しない)
-- DATEADD関数の基本構文
DATEADD(単位, 数値, 基準日付)DATEADD関数の例
以下の例では、2024年1月1日に10日を加算します。
-- SQL Server 2022
SELECT DATEADD(DAY, 10, DATEFROMPARTS(2024, 1, 1)) AS 加算結果;結果は2024年1月11日となります。
INTERVALを使った日付加算
MySQL 8.4では、日付リテラルにINTERVAL 10 DAYを加算できます。DATE_ADDでも同じ日付を求められます。
-- MySQL 8.4
SELECT DATE '2024-01-01' + INTERVAL 10 DAY AS 加算結果,
DATE_ADD(DATE '2024-01-01', INTERVAL 10 DAY) AS 関数での加算結果;どちらも2024-01-11です。MySQLのDATE_ADDは、DATEに年月日だけを加算するとDATEを返しますが、時間単位を含めるとDATETIMEを返します。戻り値は入力型と単位で変わります。MySQL公式:DATE_ADD
補足:PostgreSQLではINTERVALの書式が異なる
PostgreSQL 17ではINTERVAL '10 days'のように期間全体を文字列で指定します。date + 整数は日数を加算してdateを返し、date + intervalはtimestampを返します。PostgreSQL公式:日付・時刻の演算子
-- PostgreSQL 17
SELECT DATE '2024-01-01' + 10 AS date_result,
DATE '2024-01-01' + INTERVAL '10 days' AS timestamp_result;
-- 2024-01-11 / 2024-01-11 00:00:00加算に使う関数と入力型を確認したら、次に減算の書き方を見ていきましょう。
SQLでの日付減算の基本構文
減算は、SQL ServerではDATEADDに負の数を渡し、MySQLではDATE_SUBまたは日付からINTERVALを引く式で表せます。
DATEADD関数を使った日付減算
SQL Server 2022では、DATEADDの第2引数に負の数を指定します。以下は引数の構成を示す説明用の書式です。
-- SQL Server 2022:説明用の構文(そのまま実行しない)
-- DATEADD関数を使った日付減算
DATEADD(単位, 数値, 基準日付)DATEADD関数の例
以下の例では、2024年1月10日から10日を減算します。
-- SQL Server 2022
SELECT DATEADD(DAY, -10, DATEFROMPARTS(2024, 1, 10)) AS 減算結果;結果は2023年12月31日となります。
INTERVALを使った日付減算
MySQL 8.4では、INTERVALを引く式とDATE_SUBを使えます。
-- MySQL 8.4
SELECT DATE '2024-01-10' - INTERVAL 10 DAY AS 減算結果,
DATE_SUB(DATE '2024-01-10', INTERVAL 10 DAY) AS 関数での減算結果;この結果も2023年12月31日となります。
日付の加算と同様に、減算も簡単に行うことができます。次に、DATEADD関数の詳細な使用方法について解説します。
DATEADD関数の使用方法
DATEADD関数は、SQL Server 2022で日付を操作する関数です。特定の日付に対して日数、月数、年数などを加算または減算することができます。
DATEADD関数の構文
以下はSQL Serverの構文を説明する書式です。実行例では単位にDAYなどを、基準日付に型の付いた値を指定します。
-- SQL Server 2022:説明用の構文(そのまま実行しない)
DATEADD(単位, 数値, 基準日付)- 単位:加算または減算する時間の単位。例として、
DAY、MONTH、YEARなどがあります。 - 数値:正で加算、負で減算します。本記事のSQL Server 2022では
intの範囲が対象で、小数部は丸めず切り捨てられます。 - 基準日付:日付・時刻型の値。文字列リテラルを直接渡すと戻り値は
datetime、date型を渡すとdateになります。日付型の範囲外になる演算はエラーです。
本記事ではDATEFROMPARTS(年, 月, 日)でdate値を作り、文字列の暗黙変換を避けます。DATEADDの戻り値と制限、DATEFROMPARTSの公式仕様も参照してください。
DATEADD関数の具体例
日数の加算
以下の例では、2024年1月1日に30日を加算します。
-- SQL Server 2022
SELECT DATEADD(DAY, 30, DATEFROMPARTS(2024, 1, 1)) AS 加算結果;結果は2024年1月31日となります。
月数の加算
次の例では、2024年1月1日に3か月を加算します。
-- SQL Server 2022
SELECT DATEADD(MONTH, 3, DATEFROMPARTS(2024, 1, 1)) AS 加算結果;結果は2024年4月1日となります。
年数の加算
以下の例では、2024年1月1日に5年を加算します。
-- SQL Server 2022
SELECT DATEADD(YEAR, 5, DATEFROMPARTS(2024, 1, 1)) AS 加算結果;結果は2029年1月1日となります。
DATEADD関数の応用例
前月の月末を取得
前月末はSQL ServerのEOMONTH(基準日, -1)で求めます。日付からその日の「日」番号を引く方法でも前月末になりますが、そこからさらに1か月引く必要はありません。
-- SQL Server 2022
SELECT EOMONTH(DATEFROMPARTS(2024, 2, 15), -1) AS 前月末;結果は2024-01-31です。たとえば2月15日から15日を引いた時点で1月31日なので、さらに1か月引くと12月31日になってしまいます。
DATEADD関数を活用することで、複雑な日付操作も簡単に実行できます。次に、DATEDIFF関数を使った日付差の計算について解説します。
DATEDIFF関数での日付差の計算
SQL ServerのDATEDIFFは、2つの値の間で指定単位の境界をいくつ越えたかを返します。経過した満日数・満月数・満年数とは限りません。たとえば12月31日23時59分59秒から翌年1月1日0時までの1秒間でも、DATEDIFF(YEAR, ...)は1です。Microsoft公式:DATEDIFF
DATEDIFF関数の構文
以下はSQL Serverの説明用の構文です。MySQLの同名関数はDATEDIFF(終了日, 開始日)で、日付部分の日数差だけを返します。引数の数と順序が異なります。
-- SQL Server 2022:説明用の構文(そのまま実行しない)
DATEDIFF(単位, 開始日付, 終了日付)- 単位:数える境界。
DAY、MONTH、YEARなどを引用符なしで指定します。 - 開始日付:計算の基準となる開始の日付。
- 終了日付:計算の基準となる終了の日付。
DATEDIFF関数の具体例
日数の差を計算
以下の例では、2024年1月1日から2024年1月31日までの日数の差を計算します。
-- SQL Server 2022
SELECT DATEDIFF(DAY, DATEFROMPARTS(2024, 1, 1), DATEFROMPARTS(2024, 1, 31)) AS 日数の差;結果は30日となります。
月数の差を計算
次の例では、2024年1月1日から2024年4月1日までの月数の差を計算します。
-- SQL Server 2022
SELECT DATEDIFF(MONTH, DATEFROMPARTS(2024, 1, 1), DATEFROMPARTS(2024, 4, 1)) AS 月数の差;結果は3か月となります。
年数の差を計算
以下の例では、2020年1月1日から2024年1月1日までの年数の差を計算します。
-- SQL Server 2022
SELECT DATEDIFF(YEAR, DATEFROMPARTS(2020, 1, 1), DATEFROMPARTS(2024, 1, 1)) AS 年数の差;結果は4年となります。
DATEDIFF関数の応用例
誕生日からの年齢を計算
満年齢の計算では、その年の誕生日を迎えたかを補正します。再現できるよう、まず基準日を2024年5月14日に固定します。
-- SQL Server 2022
DECLARE @birth_date date = DATEFROMPARTS(1990, 5, 15);
DECLARE @as_of date = DATEFROMPARTS(2024, 5, 14);
SELECT CASE
WHEN @birth_date IS NULL OR @as_of IS NULL OR @as_of < @birth_date
THEN NULL
ELSE DATEDIFF(YEAR, @birth_date, @as_of)
- CASE WHEN DATEADD(YEAR,
DATEDIFF(YEAR, @birth_date, @as_of), @birth_date) > @as_of
THEN 1 ELSE 0 END
END AS 年齢;
-- 33。@as_ofを2024-05-15にすると34。当日を基準にするなら@as_ofへCAST(GETDATE() AS date)を代入します。GETDATEは時刻を含むdatetimeで、利用者の現地日付とは限らないため業務上のタイムゾーンを確認してください。この式は2月29日生まれの平年の到来日を2月28日とする方式です。3月1日を採用する場合など、業務ルールに合わせて変更します。法令上の年齢判定をそのまま置き換える式ではありません。
DATEDIFF関数を使うことで、2つの日付の間の差を簡単に計算できます。次に、実践的な日付操作の例をいくつか紹介します。
実践的な日付操作の例
実際の業務では、日付の操作はさまざまなシナリオで必要となります。以下に、いくつかの実践的な日付操作の例を紹介します。
例1: 次の月初日を取得する
特定の日付から次の月の月初日を取得する方法を紹介します。
-- SQL Server 2022
SELECT DATEADD(MONTH, 1, DATEADD(DAY, 1 - DAY(DATEFROMPARTS(2024, 1, 15)), DATEFROMPARTS(2024, 1, 15))) AS 次の月初日;この結果は2024年2月1日となります。
例2: 現在の日付から1年前の日付を取得する
現在の日付から1年前の日付を計算する方法を紹介します。
-- SQL Server 2022
SELECT DATEADD(YEAR, -1, CAST(GETDATE() AS date)) AS [1年前の日付];GETDATE()は時刻を含む値です。ここではdateへ変換してから1年を減算するため、結果は日付だけになります。365日前と1年前は、うるう年付近では一致しないことがあります。GETDATEの公式仕様
例3: 特定の期間に属するデータの抽出
時刻を含む列から2024年のデータを抽出するなら、開始を含み、翌年の開始を含まない半開区間にします。以下は既存の表を作成・変更しないSQL Server用のサンプルです。
-- SQL Server 2022
;WITH events AS (
SELECT event_id, occurred_at
FROM (VALUES
(1, CAST('2023-12-31T23:59:59.999' AS datetime2(3))),
(2, CAST('2024-01-01T00:00:00.000' AS datetime2(3))),
(3, CAST('2024-12-31T23:59:59.999' AS datetime2(3))),
(4, CAST('2025-01-01T00:00:00.000' AS datetime2(3)))
) AS v(event_id, occurred_at)
)
SELECT event_id, occurred_at
FROM events
WHERE occurred_at >= CAST('2024-01-01T00:00:00' AS datetime2(3))
AND occurred_at < CAST('2025-01-01T00:00:00' AS datetime2(3))
ORDER BY event_id;
-- event_id 2, 3BETWEENは両端を含みますが、時刻付きの列を'2024-12-31'までで比較すると、通常はその日の0時より後を含めません。翌年1月1日未満とすれば、末尾の時刻精度に依存せず12月31日全体を含められます。実テーブルでは列と境界値の型・タイムゾーンをそろえ、YEAR(列)などで列を包む前にこの範囲条件を検討します。インデックス利用の可否は実行計画で確認してください。BETWEENの公式仕様
例4: 平均処理時間を計算する
経過時間の平均には日付境界の数ではなく、必要な精度の時間差を使います。以下はUTCの値として扱うdatetime2(3)の例です。型自体にタイムゾーンは付かないため、入力を同じ基準にそろえる必要があります。
-- SQL Server 2022。開始・終了は同じUTC基準、ミリ秒精度。
;WITH runs AS (
SELECT started_at, ended_at
FROM (VALUES
(CAST('2024-01-01T23:59:59.500' AS datetime2(3)),
CAST('2024-01-02T00:00:00.250' AS datetime2(3))),
(CAST('2024-01-02T10:00:00.000' AS datetime2(3)),
CAST('2024-01-02T10:00:01.500' AS datetime2(3)))
) AS v(started_at, ended_at)
)
SELECT AVG(CAST(DATEDIFF_BIG(MILLISECOND, started_at, ended_at)
AS decimal(20, 3))) / 1000.0 AS 平均秒数
FROM runs
WHERE ended_at >= started_at;
-- (0.750 + 1.500) / 2 = 1.125秒最初の処理は日付をまたぎますが、経過時間は0.750秒です。DATEDIFF(DAY)を平均しても処理時間にはなりません。また、SQL ServerのAVG(int)はintを返すため、平均前にdecimalへ変換しています。DATEDIFF_BIGも境界数を返す関数ですが、この例は入力をミリ秒精度にそろえて計算しています。NULLや終了前の記録を集計対象に含めるかは別途決めます。DATEDIFF_BIG、AVGの戻り値
例5: 曜日を取得する
特定の日付の曜日を取得する方法を紹介します。
-- SQL Server 2022
SELECT DATENAME(WEEKDAY, DATEFROMPARTS(2024, 1, 1)) AS 曜日;2024年1月1日は月曜日です。返される曜日名はセッションの言語設定などに依存し、常に英語のMondayになるわけではありません。DATENAMEの公式仕様
これらの実践例を通して、日付操作の理解を深め、実際の業務に応用できるスキルを身につけましょう。次に、月末日付の計算方法について解説します。
応用例:月末日付の計算
業務において、月末の日付を計算する必要がある場面は多々あります。ここでは、SQLを使って月末日付を取得する方法を紹介します。
月末日付を取得する方法
月末日付を取得するには、次の月の1日から1日を減算する方法が一般的です。
SQL Serverでの例
SQL Server 2022では、EOMONTHだけで月末をdate型として取得できます。EOMONTHの公式仕様
-- SQL Server 2022
-- EOMONTH関数を使用した月末日付の取得
SELECT EOMONTH(DATEFROMPARTS(2024, 1, 15)) AS 月末日付;結果は2024年1月31日となります。
MySQLでの例
MySQLでは、LAST_DAY関数を使って月末日付を取得します。
-- MySQL 8.4
-- LAST_DAY関数を使用した月末日付の取得
SELECT LAST_DAY(DATE '2024-01-15') AS 月末日付;この結果も2024年1月31日となります。
月末日付の別の計算方法
月末日付を計算する別の方法として、DATEADD関数とDAY関数を組み合わせて計算する方法があります。
SQL Serverでの別の計算方法
いったん1か月後の日付を求め、その日付の「日」番号の分だけ日数を引くと、元の月の末日になります。
-- SQL Server 2022
-- DATEADDとDAY関数を使用した月末日付の計算
SELECT DATEADD(DAY, -DAY(DATEADD(MONTH, 1, DATEFROMPARTS(2024, 1, 15))), DATEADD(MONTH, 1, DATEFROMPARTS(2024, 1, 15))) AS 月末日付;この結果も2024年1月31日となります。
月末・うるう年では加算と減算が元に戻らないことがある
「1か月後」と「30日後」は別の計算です。SQL ServerとMySQLの月加算では、移動先に同じ日がなければ月末に調整されます。その結果、逆向きに1か月戻しても元の日付へ戻るとは限りません。
-- SQL Server 2022
SELECT DATEADD(MONTH, 1, DATEFROMPARTS(2024, 1, 31)) AS ひと月後,
DATEADD(MONTH, -1, DATEADD(MONTH, 1, DATEFROMPARTS(2024, 1, 31))) AS 戻した日,
DATEADD(YEAR, 1, DATEFROMPARTS(2024, 2, 29)) AS うるう日の翌年;
-- 2024-02-29 / 2024-01-29 / 2025-02-28-- MySQL 8.4
SELECT DATE_ADD(DATE '2024-01-31', INTERVAL 1 MONTH) AS ひと月後,
DATE_SUB(DATE_ADD(DATE '2024-01-31', INTERVAL 1 MONTH),
INTERVAL 1 MONTH) AS 戻した日,
DATE_ADD(DATE '2024-02-29', INTERVAL 1 YEAR) AS うるう日の翌年;
-- 2024-02-29 / 2024-01-29 / 2025-02-28毎月末の締め日が必要なら、前回の日付に1か月ずつ足すのではなく、対象月ごとにEOMONTHまたはLAST_DAYで月末を求めます。営業日・祝日・契約上の期限は、日付加算だけでは決まりません。
月末日付の応用例
請求書の締め日計算
MySQL 8.4で請求書の締め日を月末にする場合は、次のように計算できます。月末が休日の場合の調整は含みません。
-- MySQL 8.4
-- 請求書の締め日を月末に設定
SELECT LAST_DAY(DATE '2024-01-15') AS 締め日;これにより、指定された月の日付からその月の月末を締め日として取得できます。
これらの方法を活用することで、業務における月末日付の計算が容易になります。次に、日付の加算・減算に関する演習問題を通して、理解を深めましょう。
日付・時刻・タイムゾーンの注意点
日付だけの「翌日」、現地時刻の「翌日12時」、正確な「24時間後」は別の要件です。夏時間が切り替わる地域では、現地の1日が24時間とは限りません。タイムゾーンを持たない日時に単純加算しても、地域の夏時間ルールを自動的に適用したことにはなりません。
次はPostgreSQL 17の例です。ニューヨークの2024年3月9日12時を基準に、現地の暦で1日進めた時刻と24時間経過後を比較します。date_addの第3引数で計算する地域を指定し、出力をUTCへ変換するため、セッションの表示タイムゾーンに依存しません。
-- PostgreSQL 17。設定変更もテーブル作成も不要。
WITH sample AS (
SELECT TIMESTAMPTZ '2024-03-09 12:00:00-05' AS started_at
)
SELECT date_add(started_at, INTERVAL '1 day', 'America/New_York')
AT TIME ZONE 'UTC' AS calendar_day_utc,
(started_at + INTERVAL '24 hours')
AT TIME ZONE 'UTC' AS elapsed_24_hours_utc
FROM sample;
-- calendar_day_utc: 2024-03-10 16:00:00
-- elapsed_24_hours_utc: 2024-03-10 17:00:00前者は現地の翌日12時で、実経過は23時間です。後者は24時間後で、現地では13時になります。この挙動をSQL ServerやMySQLの構文へそのまま置き換えず、保存型、地域、比較境界を確認してください。PostgreSQL公式:date_addと夏時間、日付・時刻型とタイムゾーン
演習問題
以下はSQL Server 2022の演習です。問題5だけMySQL 8.4を使用します。コードを実行する前に期待する結果を考えてください。
問題1: 日付の加算
特定の日付に対して15日を加算するSQLクエリを作成してください。
-- SQL Server 2022
-- 問題1のクエリ
SELECT DATEADD(DAY, 15, DATEFROMPARTS(2024, 6, 1)) AS 加算結果;このクエリの結果は何になりますか?
問題2: 日付の減算
特定の日付から30日を減算するSQLクエリを作成してください。
-- SQL Server 2022
-- 問題2のクエリ
SELECT DATEADD(DAY, -30, DATEFROMPARTS(2024, 6, 1)) AS 減算結果;このクエリの結果は何になりますか?
問題3: 日付差の計算
2024年1月1日から2024年12月31日までの日数の差を計算するSQLクエリを作成してください。
-- SQL Server 2022
-- 問題3のクエリ
SELECT DATEDIFF(DAY, DATEFROMPARTS(2024, 1, 1), DATEFROMPARTS(2024, 12, 31)) AS 日数の差;このクエリの結果は何日になりますか?
問題4: 次の月初日を取得
特定の日付から次の月の月初日を取得するSQLクエリを作成してください。
-- SQL Server 2022
-- 問題4のクエリ
SELECT DATEADD(MONTH, 1, DATEADD(DAY, 1 - DAY(DATEFROMPARTS(2024, 6, 15)), DATEFROMPARTS(2024, 6, 15))) AS 次の月初日;このクエリの結果は何日になりますか?
問題5: 月末日付の取得
2024年7月15日の月末日付を取得するSQLクエリを作成してください。
-- MySQL 8.4
-- 問題5のクエリ
SELECT LAST_DAY(DATE '2024-07-15') AS 月末日付;このクエリの結果は何日になりますか?
問題6: 年齢の計算
1990年5月15日生まれの人について、2024年5月14日と誕生日当日の満年齢を計算してください。上の年齢計算と同じ方式を使います。
-- SQL Server 2022:問題6
DECLARE @birth_date date = DATEFROMPARTS(1990, 5, 15);
DECLARE @as_of date = DATEFROMPARTS(2024, 5, 14);
SELECT CASE
WHEN @birth_date IS NULL OR @as_of IS NULL OR @as_of < @birth_date
THEN NULL
ELSE DATEDIFF(YEAR, @birth_date, @as_of)
- CASE WHEN DATEADD(YEAR,
DATEDIFF(YEAR, @birth_date, @as_of), @birth_date) > @as_of
THEN 1 ELSE 0 END
END AS 年齢;
-- 33。@as_ofを2024-05-15にすると34。期待値は5月14日が33歳、5月15日が34歳です。年の境界だけを数えるDATEDIFF(YEAR)単独では、どちらも34となる点を確認してください。
演習の解答と確認ポイント
問題1は2024年6月16日、問題2は2024年5月2日、問題3は365日、問題4は2024年7月1日、問題5は2024年7月31日です。2024年はうるう年ですが、1月1日から12月31日への差は365日です。両端の日付を1日ずつ数える「日付の個数」とは区別します。問題6は誕生日の前日と当日で結果が変わります。
基本例に加えて、月末、うるう日、日付変更直前、NULL、許容範囲外の値などを使い、実際に利用するDBMSで確認しましょう。既存テーブルへ適用するときは、まずSELECTで対象と計算結果を確認し、UPDATEへ無条件に置き換えないでください。
まとめ
SQLで日付の加算・減算を行う方法について、以下のポイントを押さえておきましょう。
基本構文の理解
SQL ServerのDATEADDとMySQLのDATE_ADD・DATE_SUBを使い分けます。INTERVALの書式や計算結果の型も製品ごとに確認します。
DATEADD関数の活用
DATEADD関数を使用することで、特定の日付に対して日数、月数、年数を柔軟に加算・減算できます。負の値を指定することで減算も可能です。
DATEDIFF関数での日付差計算
SQL ServerのDATEDIFFは境界の数を返します。満年齢には誕生日の補正、経過時間には必要な精度と型の選択が必要です。MySQLのDATEDIFFとは引数も意味も同一ではありません。
実践的な応用
月末の調整やうるう年を考慮し、時刻付きの期間抽出には開始以上・次の期間開始未満の範囲を使います。暦の1日と24時間も、タイムゾーンを含めて区別してください。
演習問題での実践
演習問題を解くことで、実際にSQLを使って日付操作を試し、理解を深めることができます。
これらの知識とスキルを活用して、データベース操作の効率を向上させましょう。SQLでの日付操作に習熟することで、データ管理や分析の幅が広がります。


コメント