各投手の最後の試合のレコードを取得したいのですが、
下記SQLでは最初の試合のレコードが取れてしまいます。
* 500文字以内制限に引っかかったのでコメント欄にサンプルデータを書きます。
-- レコード挿入
INSERT INTO `pitch` VALUES(1, '2008-01-01', '岩熊', 'ソフトバンク', '●');
INSERT INTO `pitch` VALUES(2, '2008-02-02', '田中', 'ソフトバンク', '●');
INSERT INTO `pitch` VALUES(3, '2008-03-03', '浅い', '上層学院', '○');
INSERT INTO `pitch` VALUES(4, '2008-04-04', '田中', 'オリックス', '○');
INSERT INTO `pitch` VALUES(5, '2008-05-05', '岩熊', '値弁和歌山', '○');
-- これでは最初の試合が返される。
SELECT *
FROM `pitch`
GROUP BY `name`
ORDER BY max( `created_at` ) DESC
;
↑のSQLの結果は、
ID 1 (岩熊の最古)
ID 2 (田中の最古)
ID 3
が返されます。
ID 5 (岩熊の最新がほしい)
ID 4 (田中の最新がほしい)
ID 3
が返されるSQLはどう書けば良いのでしょうか?
データベースはMySQL 5です。
よろしくお願いします。
SELECT * FROM pitch p1 WHERE created_at = ( SELECT max(created_at) FROM pitch p2 WHERE p1.name = p2.name GROUP BY p2.name ) ORDER BY id;
こんなかんじ?
日時同士での一致はできるかどうか試してないから文字列に変換しないといけないかもしれない。
SELECT * FROM pichi AS T1 WHERE NOT EXISTS(SELECT * FROM pitch AS T2 WHERE T2.name = T1.name AND T2.created_at > T1.created_at) ORDER BY created_at DESC;
CREATE DATABASE `test` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
-- テーブル作成
DROP TABLE IF EXISTS `pitch`;
CREATE TABLE `test`.`pitch` (
`id` INT NOT NULL auto_increment,
`created_at` DATETIME NOT NULL ,
`name` VARCHAR( 10 ) NOT NULL ,
`vs` VARCHAR( 10 ) NOT NULL ,
`status` VARCHAR( 10 ) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci
;
-- レコード挿入
INSERT INTO `pitch` VALUES(1, '2008-01-01', '岩熊', 'ソフトバンク', '●');
INSERT INTO `pitch` VALUES(2, '2008-02-02', '田中', 'ソフトバンク', '●');
INSERT INTO `pitch` VALUES(3, '2008-03-03', '浅い', '上層学院', '○');
INSERT INTO `pitch` VALUES(4, '2008-04-04', '田中', 'オリックス', '○');
INSERT INTO `pitch` VALUES(5, '2008-05-05', '岩熊', '値弁和歌山', '○');
-- これでは最初の試合が返される。
SELECT *
FROM `pitch`
GROUP BY `name`
ORDER BY max( `created_at` ) DESC
;
ORDER BY id;
を
ORDER BY created_at DESC;
に変えるとお望みのものになります。
私の回答はb-wind氏とは少し違う形で同じことを行っていますので
よろしければ・・・。
自分でごちゃごちゃやってるうちに混乱して
ORDER BY max(created_at) DESC;
とやってしまい、気がつきませんでした。
何しろ
SELECT created_at FROM pitch p2
WHERE p1.name = p2.name
の意図もさっぱり理解できず...
kn1968さんのSQLはさらにちんぷんかんぷんで(^^;;
皆さんありがとうございました。
以下はpitchの中で”名前が同じ”で”日付が新しいもの”が別レコードとして存在していれば
そのレコードは対象から外すということになります。
WHERE NOT EXISTS(SELECT * FROM pitch AS T2 WHERE T2.name = T1.name AND T2.created_at > T1.created_at)
T1やT2はエイリアス(別名)と呼ばれ、長いテーブル名を読みやすく短くする意味もあれば
1つのSQL内で同じテーブルをあたかも別々のテーブルであるかの如く使う場合にも使います。
pitch AS T1 と pitch AS T2 は元は同じpitchなのだけれども
同じものが二つあるものとして扱っている訳です。
ちなみにMySQLではASは省略できるのでpitch T1やpitch T2などの書き方でもOKです。
私は文法ミスをおかさないようにASを付けるのを習慣としているだけでMySQLを主として
お使いの方々は省略するのが通例のようです。
ANYも似たようなものですが特定のカラムの情報を抜き出して全て比較するという手順のため
単純に該当有無だけを対象とするEXISTSよりも柔軟に対応できる分、速度は落ちます。
今回の場合は処理の流れとしてはいずれも同じで
(1)FROM で指定されているテーブルから1レコード読み取られる
(2)WHERE で条件に合致するかを検討する。
(3)最終レコードでなければ(1)に戻る
(4)ORDER BY 並び順を決定する。
(5)SELECT 指定されたカラムを返す。
というような流れだと考えれば理解しやすいでしょう。
実際の内部動作を表しているのではなく、理解しやすいように書いています。
大変くわしい解説をいただき、深々感謝です!
ありがとうございますm(_ _)m