MySQLでDate関数同士を比較するときの注意
MySQLには日付の計算を行う関数がいくつかあって、例えば当日は
mysql> SELECT NOW();
- ---------------------+
NOW()
- ---------------------+
2012-04-23 16:26:11
- ---------------------+
1 row in set (0.00 sec)
前日は
mysql> SELECT NOW() - interval 1 day;
- ------------------------+
NOW() - interval 1 day
- ------------------------+
2012-04-22 16:28:17
- ------------------------+
1 row in set (0.00 sec)
で、これを日付だけ取り出したい場合、Date()を使う
mysql> SELECT date(NOW() - interval 1 day);
- ------------------------------+
date(NOW() - interval 1 day)
- ------------------------------+
2012-04-22
- ------------------------------+
1 row in set (0.00 sec)
単体で動かしているならこれで問題ないんだけど、Date()同士の引き算の結果がおかしくて軽くハマったので備忘録
まず同一月の引き算
mysql> SELECT DATE(NOW());
- -------------+
DATE(NOW())
- -------------+
2012-04-23
- -------------+
1 row in set (0.00 sec);
mysql> SELECT DATE(NOW() - INTERVAL 1 DAY);
- ------------------------------+
DATE(NOW() - INTERVAL 1 DAY)
- ------------------------------+
2012-04-22
- ------------------------------+
1 row in set (0.00 sec);
mysql> SELECT DATE(NOW()) - DATE(NOW() - INTERVAL 1 DAY);
- --------------------------------------------+
DATE(NOW()) - DATE(NOW() - INTERVAL 1 DAY)
- --------------------------------------------+
1
- --------------------------------------------+
1 row in set (0.00 sec)
同月同士なら全く問題なく計算できる。これが月をまたぐと全くおかしくなる。
!?mysql> SELECT DATE(NOW());
- -------------+
DATE(NOW())
- -------------+
2012-04-23
- -------------+
1 row in set (0.00 sec)
mysql> SELECT DATE(NOW() - INTERVAL 23 DAY);
- -------------------------------+
DATE(NOW() - INTERVAL 23 DAY)
- -------------------------------+
2012-03-31
- -------------------------------+
1 row in set (0.00 sec)
mysql> SELECT DATE(NOW()) - DATE(NOW() - INTERVAL 23 DAY);
- ---------------------------------------------+
DATE(NOW()) - DATE(NOW() - INTERVAL 23 DAY)
- ---------------------------------------------+
92
- ---------------------------------------------+
1 row in set (0.01 sec)
どうも日付同士の演算をする場合、Date()だと年を365日、月を30 or 31 or 29として計算し直すのではなく、単純に年、月を10進数で+1桁としているようだ。
だからひと月前は30日ではなく、100、年は1000が足されたような格好になる。
なので日付どうしの計算を行う場合は、ちゃんとTO_DAYSを使いましょう。
mysql> SELECT TO_DAYS(NOW()) - TO_DAYS(NOW() - INTERVAL 23 DAY);
- ---------------------------------------------------+
TO_DAYS(NOW()) - TO_DAYS(NOW() - INTERVAL 23 DAY)
- ---------------------------------------------------+
23
- ---------------------------------------------------+
1 row in set (0.00 sec)
もしくはDATEDIFF
mysql> SELECT DATEDIFF(DATE(NOW()), DATE(NOW() - INTERVAL 23 DAY));
- ------------------------------------------------------+
DATEDIFF(DATE(NOW()), DATE(NOW() - INTERVAL 23 DAY))
- ------------------------------------------------------+
23
- ------------------------------------------------------+
1 row in set (0.00 sec)
使用頻度はどっちが高いんだろう。