2017-12-12 6 views
3

基本的に私が望むのは、記録保持者と最善の時間ですべてのレース記録を選択できるということです。私は同様のクエリを調べ、残りのクエリよりも速い3つのクエリを見つけることができました。GROUP BY + HAVING行を無視する

問題は、ユーザーID 2がレコードを所有しているレースを完全に無視していることです。

これらは私のテーブル、インデックス、およびいくつかのサンプルデータです:

CREATE TABLE `races` (
`raceid` smallint(5) unsigned NOT NULL AUTO_INCREMENT, 
`name` varchar(20) NOT NULL, 
PRIMARY KEY (`raceid`), 
UNIQUE KEY `name` (`name`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

CREATE TABLE `users` (
`userid` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, 
`name` varchar(20) NOT NULL, 
PRIMARY KEY (`userid`), 
UNIQUE KEY `name` (`name`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

CREATE TABLE `race_times` (
`raceid` smallint(5) unsigned NOT NULL, 
`userid` mediumint(8) unsigned NOT NULL, 
`time` mediumint(8) unsigned NOT NULL, 
PRIMARY KEY (`raceid`,`userid`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

INSERT INTO `races` (`raceid`, `name`) VALUES 
(1, 'Doherty'), 
(3, 'Easter Basin Naval S'), 
(5, 'Flint County'), 
(6, 'Fort Carson'), 
(4, 'Glen Park'), 
(2, 'Palomino Creek'), 
(7, 'Tierra Robada'); 

INSERT INTO `users` (`userid`, `name`) VALUES 
(1, 'Player 1'), 
(2, 'Player 2'); 

INSERT INTO `race_times` (`raceid`, `userid`, `time`) VALUES 
(1, 1, 51637), 
(1, 2, 50000), 
(2, 1, 148039), 
(3, 1, 120516), 
(3, 2, 124773), 
(4, 1, 101109), 
(6, 1, 89092), 
(6, 2, 89557), 
(7, 1, 77933), 
(7, 2, 78038); 

私はこれらの2つのクエリ実行のであれば:

SELECT rt1.raceid, r.name, rt1.userid, p.name, rt1.time 
FROM race_times rt1 
LEFT JOIN users p ON (rt1.userid = p.userid) 
JOIN races r ON (r.raceid = rt1.raceid) 
WHERE rt1.time = (SELECT MIN(rt2.time) FROM race_times rt2 WHERE rt1.raceid = rt2.raceid) 
GROUP BY r.name; 

か...

SELECT rt1.*, r.name, p.name 
FROM race_times rt1 
LEFT JOIN users p ON p.userid = rt1.userid 
JOIN races r ON r.raceid = rt1.raceid 
WHERE EXISTS (SELECT NULL FROM race_times rt2 WHERE rt2.raceid = rt1.raceid 
GROUP BY rt2.raceid HAVING MIN(rt2.time) >= rt1.time); 

を私が受け取ります次のように正しい結果が得られます。

raceid | name     | userid | name  | time | 
-------+----------------------+--------+----------+--------| 
1  | Doherty    | 2  | Player 2 | 50000 | 
3  | Easter Basin Naval S | 1  | Player 1 | 120516 | 
6  | Fort Carson   | 1  | Player 1 | 89092 | 
4  | Glen Park   | 1  | Player 1 | 101109 | 
2  | Palomino Creek  | 1  | Player 1 | 148039 | 
7  | Tierra Robada  | 1  | Player 1 | 77933 | 

、ここで故障したクエリです:

SELECT rt.raceid, r.name, rt.userid, p.name, rt.time 
FROM race_times rt 
LEFT JOIN users p ON p.userid = rt.userid 
JOIN races r ON r.raceid = rt.raceid 
GROUP BY r.name 
HAVING rt.time = MIN(rt.time); 

と結果がこれです:あなたが見ることができるように

raceid | name     | userid | name  | time | 
-------+----------------------+--------+----------+--------| 
3  | Easter Basin Naval S | 1  | Player 1 | 120516 | 
6  | Fort Carson   | 1  | Player 1 | 89092 | 
4  | Glen Park   | 1  | Player 1 | 101109 | 
2  | Palomino Creek  | 1  | Player 1 | 148039 | 
7  | Tierra Robada  | 1  | Player 1 | 77933 | 

、レース "ドハーティ"(raceid:1)はプレーヤー」が所有しています2 "(userid:2)と残りのレースレコード(これはすべてuserid1が所有している)と一緒には表示されません。何が問題ですか?

よろしくお願いします。

+0

最初のクエリは無意味なので、違う定義があると思います!! DDLの提供にはうってつけですが、希望の結果をテキストとして提供してください。 – Strawberry

+0

@Strawberry私は 'WHERE'節でサブクエリを避けるべきであることを他のスレッドで読んでいましたが、私は' EXISTS'を使って他のクエリの効率について確信していませんでした。私はまた、結果を絵からテキストに変更しました。ありがとうございました。 –

+0

それは望ましい結果ですか? – Strawberry

答えて

0

クエリはすべての結果を取得し、それに基づいてさらにフィルタリングします。 GROUP BYはグループに基づいて行を圧縮し、各セットの最初のエントリを提供します。プレーヤー1はレース1の最初のエントリーであるため、それはHAVINGによって処理されている結果です。その後、その時間はグループ結果のMIN(時間)と等しくないため、フィルタリングされます。

これは、あなたが投稿した他のものがサブクエリを使用している理由です。私の個人的な好みは最初の例のためであり、私にとってそれは少し読みやすくなっています。パフォーマンスは同じでなければなりません。

where句でサブクエリを実行しようとするのは悪い考えではありませんが、これはJOINで同じ結果を達成できるときにはほとんど有効です。それ以外の場合は、JOINで結果を取得することができず、サブクエリが必要です。