MySQL 9.
これらは WL#16895: Refactor DATE handling in server によるDATE型の扱いの見直しに関連する修正です。Worklogを見ると、サーバー内部でDATE値を扱う際に利用していたMYSQL_
内部実装の変更と聞くと、普段利用するSQLへの影響はあまりなさそうにも見えます。しかし、リリースノートには実際の関数の修正も複数挙がっています。ということで今回は、MySQL 8.
今回のsql_
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,
ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
設定の差ではなく、バージョン差として結果を比較します。
0年の日付演算
まずは、リリースノートにも記載されている0年の日付演算です。今回は、日付演算の境界値として0000-01-01を用います。0000-00-00は、MySQLで特別な意味を持つゼロ日付です。普段のアプリケーションで0年の日付を明示的に使う機会は多くないと思いますが、境界値に対する日付演算の結果は気になるところです。0年1月1日と1月31日に1日を加算してみます。
mysql8.4.11> SELECT
-> ADDDATE('0000-01-01', INTERVAL 1 DAY) AS jan_1,
-> ADDDATE('0000-01-31', INTERVAL 1 DAY) AS jan_31;
+------------+------------+
| jan_1 | jan_31 |
+------------+------------+
| 0000-00-00 | 0000-00-00 |
+------------+------------+
mysql9.7.2> SELECT
-> ADDDATE('0000-01-01', INTERVAL 1 DAY) AS jan_1,
-> ADDDATE('0000-01-31', INTERVAL 1 DAY) AS jan_31;
+------------+------------+
| jan_1 | jan_31 |
+------------+------------+
| 0000-01-02 | 0000-02-01 |
+------------+------------+
8.0000-00-00になりました。一方、9.0000-01-02および0000-02-01となり、月またぎを含めて日付として計算した結果が返っています。
次に、TO_
mysql8.4.11> SELECT TO_DAYS('0000-01-01'), FROM_DAYS(1);
+------------------------+--------------+
| TO_DAYS('0000-01-01') | FROM_DAYS(1) |
+------------------------+--------------+
| 1 | 0000-00-00 |
+------------------------+--------------+
mysql9.7.2> SELECT TO_DAYS('0000-01-01'), FROM_DAYS(1);
+------------------------+--------------+
| TO_DAYS('0000-01-01') | FROM_DAYS(1) |
+------------------------+--------------+
| 1 | 0000-01-01 |
+------------------------+--------------+
TO_の結果は、両方とも1です。しかし、8.0000-00-00となり、この値では変換の往復が成立していません。9.0000-01-01を返すため、往復できるようになっています。
DATEとDATETIMEを混ぜたTIMEDIFF()
次に、TIMEDIFF()の引数にDATETIMEとDATEを混ぜた場合です。
mysql8.4.11> SELECT
-> TIMEDIFF('2026-08-24 12:00:00', '2026-08-23') AS diff1,
-> TIMEDIFF('2026-08-23', '2026-08-24 12:00:00') AS diff2;
+-------+-------+
| diff1 | diff2 |
+-------+-------+
| NULL | NULL |
+-------+-------+
mysql9.7.2> SELECT
-> TIMEDIFF('2026-08-24 12:00:00', '2026-08-23') AS diff1,
-> TIMEDIFF('2026-08-23', '2026-08-24 12:00:00') AS diff2;
+-----------+------------+
| diff1 | diff2 |
+-----------+------------+
| 36:00:00 | -36:00:00 |
+-----------+------------+
8.36:00:00と-36:00:00が返ります。この結果から、今回のTIMEDIFF()ではDATE側がその日の00:00:00として扱われ、DATETIMEとの差分が計算されていることがわかります。
8.
DATEをBIGINTへコピーしてみる
続いて、DATE列の値をBIGINT列へINSERT ... SELECTした場合を確認します。
CREATE TABLE src (d DATE);
CREATE TABLE dst (n BIGINT);
INSERT INTO src VALUES ('2026-08-23');
INSERT INTO dst SELECT d FROM src;
SELECT n FROM dst;
結果は以下のようになりました。
mysql8.4.11> SELECT n FROM dst; +----------------+ | n | +----------------+ | 20260823000000 | +----------------+ mysql9.7.2> SELECT n FROM dst; +----------+ | n | +----------+ | 20260823 | +----------+
8.20260823000000、9.20260823です。8.
必要な形式が決まっているなら、暗黙変換に任せない方が安全です。8桁のYYYYMMDDが必要な場合はCAST(d AS UNSIGNED)、14桁のYYYYMMDD000000が必要な場合はCAST(DATE_のように明示できます。
補足:DAYNAME()を数値演算に入れた場合
DAYNAME()を数値演算に入れた場合も確認してみます。これはあまり実用的な式ではありませんが、9.
mysql8.4.11> SELECT
-> DAYNAME('2026-08-23') AS day_name,
-> DAYNAME('2026-08-23') + 0 AS dayname_plus_zero,
-> WEEKDAY('2026-08-23') AS weekday;
+----------+-------------------+---------+
| day_name | dayname_plus_zero | weekday |
+----------+-------------------+---------+
| Sunday | 6 | 6 |
+----------+-------------------+---------+
mysql9.7.2> SELECT
-> DAYNAME('2026-08-23') AS day_name,
-> DAYNAME('2026-08-23') + 0 AS dayname_plus_zero,
-> WEEKDAY('2026-08-23') AS weekday;
+----------+-------------------+---------+
| day_name | dayname_plus_zero | weekday |
+----------+-------------------+---------+
| Sunday | 0 | 6 |
+----------+-------------------+---------+
なお、今回の検証環境ではlc_DAYNAME('2026-08-23')はSundayを返します。DAYNAME()単体は、どちらのバージョンでも曜日名の Sunday を返しています。しかし8.
曜日番号が必要な場合は、DAYNAME()を数値へ変換するのではなく、最初からWEEKDAY()またはDAYOFWEEK()を利用すべきでしょう。なお、WEEKDAY()は月曜日を0、DAYOFWEEK()は日曜日を1として数えます。
まとめ
今回は、MySQL 8.
0年の日付演算やFROM_