今週作成されたレコードを取得する

例えば以下のようなテーブルがあったとして、

mysql> SHOW FIELDS FROM `posts`;
+----------+------------------+------+-----+---------+----------------+
| Field    | Type             | Null | Key | Default | Extra          |
+----------+------------------+------+-----+---------+----------------+
| id       | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| title    | varchar(100)     | NO   |     |         |                |
| body     | text             | NO   |     |         |                |
| created  | datetime         | NO   |     |         |                |
| modified | datetime         | NO   |     |         |                |
+----------+------------------+------+-----+---------+----------------+
5 rows in set (0.02 sec)

基準となる日、タイトル通り”今週”なら今週の週初め(ここでは日曜日とします)さえ取得されれば、MySQLの場合、

SELECT * FROM `posts` WHERE `created` >= '2011-11-20' AND `created` < DATE_ADD('2011-11-20', INTERVAL 7 DAY);

と書けますが、

SELECT * FROM `posts` WHERE YEARWEEK( NOW() ) = YEARWEEK(`created`);

でも今週日曜日以降の一週間に作成されたレコードを取得できます。

MySQLのYEARWEEK(date[, mode])

  1. 日付
  2. 第一週の扱い方

といった最大2つの引数から年4桁週番号2桁で構成された6桁の値を返します。ちなみにISO 8601はサポートしてないらしいので、ここではじき出される週番号はmodeをあれこれ触ってもPerlにおけるTime::PieceのweekメソッドやPHPのdate("W")で返る週番号とは、特に年末年始辺りの日付で食い違いやすいです(なので、そこから導き出した週番号と比較すると期待する結果が出ないことも)。

なお、第二引数は

引用はhttp://dev.mysql.com/doc/refman/5.1/ja/date-and-time-functions.htmlから
モード 開始日曜日 範囲 Week 1 は下記の最初の週…
0 日曜日 0-53 この年の日曜日
1 月曜日 0-53 この年は 3 日以上
2 日曜日 1-53 この年は日曜日
3 月曜日 1-53 この年は 3 日以上
4 日曜日 0-53 この年は 3 日以上
5 月曜日 0-53 この年は月曜日
6 日曜日 1-53 この年は 3 日以上
7 月曜日 1-53 この年は月曜日

となってます。

この手の処理をSQLで求めようとするとまず最初にWEEK()が目に付きがちですが、この場合は週番号だけしか返さないので過去の同一週番号もヒットしてしまいます。というか、正にそういうバグを抱えたプログラムを見かけたのが、このエントリのきっかけだったりするのですが……。

ただ、YEARWEEK()は早くないので、使いどころは間違いないようにしたいところです。