MySQLでDate関数同士を比較するときの注意

MySQLには日付の計算を行う関数がいくつかあって、例えば当日は


mysql> SELECT NOW();

  1. ---------------------+
NOW()
  1. ---------------------+
2012-04-23 16:26:11
  1. ---------------------+

1 row in set (0.00 sec)

前日は

mysql> SELECT NOW() - interval 1 day;

  1. ------------------------+
NOW() - interval 1 day
  1. ------------------------+
2012-04-22 16:28:17
  1. ------------------------+

1 row in set (0.00 sec)

で、これを日付だけ取り出したい場合、Date()を使う

mysql> SELECT date(NOW() - interval 1 day);

  1. ------------------------------+
date(NOW() - interval 1 day)
  1. ------------------------------+
2012-04-22
  1. ------------------------------+

1 row in set (0.00 sec)

単体で動かしているならこれで問題ないんだけど、Date()同士の引き算の結果がおかしくて軽くハマったので備忘録
まず同一月の引き算

mysql> SELECT DATE(NOW());

  1. -------------+
DATE(NOW())
  1. -------------+
2012-04-23
  1. -------------+

1 row in set (0.00 sec);

mysql> SELECT DATE(NOW() - INTERVAL 1 DAY);

  1. ------------------------------+
DATE(NOW() - INTERVAL 1 DAY)
  1. ------------------------------+
2012-04-22
  1. ------------------------------+

1 row in set (0.00 sec);

mysql> SELECT DATE(NOW()) - DATE(NOW() - INTERVAL 1 DAY);

  1. --------------------------------------------+
DATE(NOW()) - DATE(NOW() - INTERVAL 1 DAY)
  1. --------------------------------------------+
1
  1. --------------------------------------------+

1 row in set (0.00 sec)

同月同士なら全く問題なく計算できる。これが月をまたぐと全くおかしくなる。

mysql> SELECT DATE(NOW());

  1. -------------+
DATE(NOW())
  1. -------------+
2012-04-23
  1. -------------+

1 row in set (0.00 sec)

mysql> SELECT DATE(NOW() - INTERVAL 23 DAY);

  1. -------------------------------+
DATE(NOW() - INTERVAL 23 DAY)
  1. -------------------------------+
2012-03-31
  1. -------------------------------+

1 row in set (0.00 sec)

mysql> SELECT DATE(NOW()) - DATE(NOW() - INTERVAL 23 DAY);

  1. ---------------------------------------------+
DATE(NOW()) - DATE(NOW() - INTERVAL 23 DAY)
  1. ---------------------------------------------+
92
  1. ---------------------------------------------+

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);

  1. ---------------------------------------------------+
TO_DAYS(NOW()) - TO_DAYS(NOW() - INTERVAL 23 DAY)
  1. ---------------------------------------------------+
23
  1. ---------------------------------------------------+

1 row in set (0.00 sec)

もしくはDATEDIFF

mysql> SELECT DATEDIFF(DATE(NOW()), DATE(NOW() - INTERVAL 23 DAY));

  1. ------------------------------------------------------+
DATEDIFF(DATE(NOW()), DATE(NOW() - INTERVAL 23 DAY))
  1. ------------------------------------------------------+
23
  1. ------------------------------------------------------+

1 row in set (0.00 sec)

使用頻度はどっちが高いんだろう。