« 中だるみ継続中… | メイン | XXXHOLiC シリーズ »

2007年05月31日

MySQL の DATETIME 型の日付の取り扱い

挿入日時を記録するために DATETIME 型を利用しているのですが、その日付の取り扱いに悩まされたので、書いてみる。

mysql> DESCRIBE hoge;
+-------+----------+------+-----+---------------------+-------+
| Field | Type     | Null | Key | Default             | Extra |
+-------+----------+------+-----+---------------------+-------+
| id    | int(11)  |      |     | 0                   |       |
| cdate | datetime |      |     | 0000-00-00 00:00:00 |       |
+-------+----------+------+-----+---------------------+-------+
2 rows in set (0.00 sec)

上記のようなテストテーブルを作成しました。挿入データは INT, DATETIME のみです。

mysql> SELECT * FROM hoge;
+----+---------------------+
| id | cdate               |
+----+---------------------+
|  0 | 2007-01-01 00:00:00 |
|  1 | 2007-01-01 00:00:05 |
+----+---------------------+
2 rows in set (0.00 sec)

挿入したデータは、上記の2種類。時刻を 0 で埋めたものを埋めていないものです。

日付値を前提とする関数は、通常、日付時刻値を受け入れて、時刻部分を無視します。

ドキュメントには、前記のように書いていたので、以下のようなクエリを投げてみます。

mysql> SELECT * FROM hoge WHERE cdate = '2007-01-01';
+----+---------------------+
| id | cdate               |
+----+---------------------+
|  0 | 2007-01-01 00:00:00 |
+----+---------------------+
1 row in set (0.00 sec)

ドキュメントから読み取った予想としては、日付で比較するのだから 2 rows の結果が欲しかったのです。すなわち、すでに挿入されてるデータの cdate が 2007-01-01 と解釈されて欲しかった。でもそうじゃない。

mysql> SELECT * FROM hoge WHERE cdate >= '2007-01-01';
+----+---------------------+
| id | cdate               |
+----+---------------------+
|  0 | 2007-01-01 00:00:00 |
|  1 | 2007-01-01 00:00:05 |
+----+---------------------+
2 rows in set (0.00 sec)

大なりイコールにすると 2 rows となるので、対象として与えた 2007-01-01 は、内部で 2007-01-01 00:00:00 と解釈されてる模様。

MySQL 4.1.20 を利用しているので、関数 DATE が利用できる。この関数は、まさに DATETIME 型を DATE 型に変換する関数です。

mysql> SELECT * FROM hoge WHERE DATE(cdate) = '2007-01-01';
+----+---------------------+
| id | cdate               |
+----+---------------------+
|  0 | 2007-01-01 00:00:00 |
|  1 | 2007-01-01 00:00:05 |
+----+---------------------+
2 rows in set (0.00 sec)

期待通りの結果に!

うだうだ書いたわけですが、僕のドキュメントの読み間違いが原因です。「日付時刻値を受け入れて、時刻部分を無視します」の後者を読んで勘違いしたわけです。前者もきちんと読めと…。

ドキュメント解釈ミスが起こりうるので、テストをきちんとしようと再確認した出来事でした。

【関連情報】
・6.3.4. 日付と時刻関数 - MySQL 4.1 リファレンスマニュアル
 http://dev.mysql.com/doc/refman/4.1/ja/date-and-time-functions.html

2007年05月31日 14:31 | Technology

トラックバック

このリストは、次のエントリーを参照しています: MySQL の DATETIME 型の日付の取り扱い:

» MySQLでDATETIME型のデータを高速に検索する方法 from 深追い Fukaoi.org
MySQLでDATETIME型のカラムを追加して、YYYY-MM-DD HH:MM:SSの形式でデータを保存することはよくあるケースだと 思う。DATET... [続きを読む]

トラックバック時刻: 2009年03月17日 00:27

コメント

「関数は」が重要なのでは。

投稿者 斎藤ただし : 2007年05月31日 16:08

>> 斎藤ただし さん
「型」も広義の「関数」だと思うのだけど、どうなんでしょう。
いずれにせよ、ドキュメントの読み間違いです…。恥ずかしい :(

投稿者 ceekz : 2007年06月01日 02:13

古いエントリへのコメントで恐縮ですが、
大規模なDBの場合には検索にインデックスを使えるかどうかが決定的に効いてくるので、
『cdate >= '2007-01-01' and cdate < '2007-01-02'』にもメリットはあるはず。たぶん。

投稿者 kaigai : 2007年09月25日 22:24

>> kaigai さん
検証の必要がありますが、確かにそうですね。深い…。

投稿者 ceekz : 2007年09月27日 16:11