MySQLで現在の日付を取得する関数として、CURDATE()とSYSDATE()が存在します。
いずれも現在の日付を取得する関数なので、一見同じものに見えますが、実行結果に違いがあります。
違いを意識せず使っていると思わぬ不具合の原因となるので、違いをまとめておこうと思います。(私は事故りました。。。)
MySQL CURDATE()とSYSDATE()の違い
CURDATE()とSYSDATE()の違いは日付を返却するか、日時を返却するかです。
CURDATE()は日付を返却します。
SYSDATE()は日時を返却します。
実際の実行結果は以下のようになります。
SELECT CURDATE(), SYSDATE() FROM DUAL;
CURDATE() | SYSDATE() |
2021-02-24 | 2021-02-24 10:41:23 |
このように、返却結果に違いがあることが分かります。
ちなみに、「CURRENT_DATE」と「CURRENT_DATE()」はCURDATE()のシノニム(別名)であるため、CURDATE()と同じ動きをします。
また、「NOW()」はSYSDATE()のシノニム(別名)であるため、SYSDATE()と同じ動きをします。
SELECT CURDATE(),CURRENT_DATE, CURRENT_DATE(), SYSDATE(), NOW() FROM DUAL;
以下のようになります。
CURDATE() | CURRENT_DATE | CURRENT_DATE() | SYSDATE() | NOW() |
2021-02-24 | 2021-02-24 | 2021-02-24 | 2021-02-24 10:41:23 | 2021-02-24 10:41:23 |
MySQL CURDATE()とSYSDATE()を適当に使うと起きる不具合
CURDATE()とSYSDATE()には日付、日時と取得結果に差異があります。
そのため、比較処理を書く場合に不具合が起きるケースがあります。
以下でサンプルデータを使用し、注意したほうが良いSQLのサンプルを残しておきます。
サンプルテーブルとデータ作成
CREATE TABLE PERSONAL ( ID VARCHAR(20) BINARY NOT NULL, START_DATE DATE NOT NULL, LAST_NAME_KANJI VARCHAR(30) BINARY NOT NULL, FIRST_NAME_KANJI VARCHAR(30) BINARY NOT NULL, PRIMARY KEY (ID, START_DATE) ); INSERT INTO PERSPONAL (`ID`,`START_DATE`,`LAST_NAME_KANJI`,`FIRST_NAME_KANJI`) VALUES ('1','2021-02-24','田中','太朗') ,('2','2021-02-23','鈴木','次郎') ,('3','2021-02-25','山田','三郎');
全件取得すると、以下のようになります。
SELECT * FROM PERSONAL;
ID | START_DATE | LAST_NAME_KANJI | FIRST_NAME_KANJI |
1 | 2021-02-24 | 田中 | 太朗 |
2 | 2021-02-23 | 鈴木 | 次郎 |
3 | 2021-02-25 | 山田 | 三郎 |
不具合が起きるケース
「START_DATEが本日(2021年2月24日)以降」のデータを取得したいケースを考えます。24日と25日のレコードが取得したいです。
SELECT * FROM PERSONAL WHERE START_DATE >= CURDATE(); SELECT * FROM PERSONAL WHERE START_DATE >= SYSDATE();
CURDATE()のときの結果は以下の通りで、期待していたデータが取得できました。
ID | START_DATE | LAST_NAME_KANJI | FIRST_NAME_KANJI |
1 | 2021-02-24 | 田中 | 太朗 |
3 | 2021-02-25 | 山田 | 三郎 |
しかし、SYSDATE()の場合は以下の通りになってしまい、期待していたデータが取得できていません。
ID | START_DATE | LAST_NAME_KANJI | FIRST_NAME_KANJI |
3 | 2021-02-25 | 山田 | 三郎 |
こうなってしまう原因は、SYSDATEの場合、実際には以下のような比較が行われているためです。
START_DATE(2021-02-24 00:00:00) >= SYSDATE()(2021-02-24 10:51:21)
SYSDATE()は日時込みで比較するため、2/24のレコードは対象とならなかったのですね。
このように、CURDATE()とSYSDATE()には差異があるので、特に比較で使用する場合は、思わぬ不具合が発生しないよう注意が必要です。
※JavaでもDate型で似たような不具合の可能性があります。記事がありますので興味のある方はご覧ください。
まとめ
MySQLのCURDATE()とSYSDATEはそれぞれ、日付を取得/日時を取得という差異があります。
それを意識せずに使っていると、思わぬ不具合が発生する可能性があります。
不具合が起きると、SQLの一部にさりげなく書かれており、発見に意外と時間がかかるため、プロジェクト内で日時/日付の扱い方について共通の認識を持つようにすることをおススメします。
実用的なSQLの書き方や注意点を勉強する場合、ミックさんという方が書いている参考書がおススメです!
業務やプロダクトでSQLを書く場合は、必携といってもいいほど実用的な書き方を学ぶことができるので私も重宝している1冊です。