group byはorder byより先に処理される。これ重要。
今日はちょっとだけはまったSQLの話し。例えばブログのエントリーについたコメントが新しい順にエントリーをソートしたいときを考えてみます。
テーブル構成はこんな感じ。
CREATE TABLE `entry` (
`id` int(11) NOT NULL auto_increment,
`title` text,
`body` text,
`created_at` datetime default NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `comment` (
`id` int(11) NOT NULL auto_increment,
`entry_id` int,
`body` text,
`created_at` datetime default NULL,
PRIMARY KEY (`id`)
);
で、入ってるデータはこんなん。
mysql> select * from entry;
+----+--------+-------+---------------------+
| id | title | body | created_at |
+----+--------+-------+---------------------+
| 1 | title1 | body1 | 2009-01-01 12:00:00 |
| 2 | title2 | body2 | 2009-01-02 12:00:00 |
| 3 | title3 | body3 | 2009-01-03 12:00:00 |
+----+--------+-------+---------------------+
mysql> select * from comment;
+----+----------+----------+---------------------+
| id | entry_id | body | created_at |
+----+----------+----------+---------------------+
| 1 | 1 | comment1 | 2009-01-04 12:00:00 |
| 2 | 2 | comment2 | 2009-01-05 12:00:00 |
| 3 | 3 | comment3 | 2009-01-06 12:00:00 |
| 4 | 3 | comment4 | 2009-01-07 12:00:00 |
| 5 | 2 | comment5 | 2009-01-08 12:00:00 |
| 6 | 1 | comment6 | 2009-01-09 12:00:00 |
+----+----------+----------+---------------------+
これを、新しいコメントがついた順にエントリーをソートしようとすると、entry_idは1,2,3の順にならないといけないですよね。
で、下記のようなSQLを書いてみたら全然期待しない結果になりました。
mysql> select * from comment group by entry_id order by created_at desc;
+----+----------+----------+---------------------+
| id | entry_id | body | created_at |
+----+----------+----------+---------------------+
| 3 | 3 | comment3 | 2009-01-06 12:00:00 |
| 2 | 2 | comment2 | 2009-01-05 12:00:00 |
| 1 | 1 | comment1 | 2009-01-04 12:00:00 |
+----+----------+----------+---------------------+
これはorder byよりgroup byが先に処理されるからです。以下の様に書けばよさげ。
mysql> select id,entry_id,body,created_at,max(created_at) as max_date from comment group by entry_id order by max_date desc;
+----+----------+----------+---------------------+---------------------+
| id | entry_id | body | created_at | max_date |
+----+----------+----------+---------------------+---------------------+
| 1 | 1 | comment1 | 2009-01-04 12:00:00 | 2009-01-09 12:00:00 |
| 2 | 2 | comment2 | 2009-01-05 12:00:00 | 2009-01-08 12:00:00 |
| 3 | 3 | comment3 | 2009-01-06 12:00:00 | 2009-01-07 12:00:00 |
+----+----------+----------+---------------------+---------------------+
selectするときにソートするカラムの最大値を取得しておいて、その値でソートします。こういうのってデータによっては間違ったSQLでも期待通りの値が返ってくることがあるから要注意。
ORMで育ったゆとり世代でホントすいません。
- Prev Entry:Vimで同じインデントの部分を選択する
- Next Entry:vimでquickfixを自動で開く