2017-12-12 3 views
3

기본적으로 내가 원하는 것은 기록 보유자와 최적의 시간으로 모든 레이스 기록을 선택할 수 있다는 것입니다. 비슷한 검색어에 대해 조사한 결과 나머지 3 가지 검색어보다 빠른 3 가지 검색어를 찾았습니다.GROUP BY + HAVING 행 무시

문제는 사용자 2가 기록을 소유하고있는 경주를 완전히 무시한다는 것입니다.

이 일부 샘플 데이터 내 테이블, 인덱스, 그리고 : 나는이 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); 

:

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); 

내가받을 아래와 같이 정확한 결과를 얻으십시오 :

,210

여기가 결함이있는 쿼리입니다 :

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 : 1)
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 | 

플레이어 "가 소유 2 "(userid : 2)이며 나머지 레이스 레코드 (userid 1이 모두 소유 함)와 함께 표시되지 않습니다. 문제가 무엇입니까?

감사합니다.

+0

첫 번째 쿼리는 무의미합니다. 그래서 우리는 결함에 대한 다른 정의가 있다고 생각합니다 !! DDL을 제공하는 것이 좋지만 원하는 결과를 텍스트로 제공하십시오. – Strawberry

+0

@Strawberry 다른 쓰레드에서'WHERE' 절에서 서브 쿼리를 피해야한다고 읽었습니다.'EXISTS'를 사용하는 다른 쿼리의 효율성에 대해서는 확신 할 수 없었습니다. 결과를 그림에서 텍스트로 변경했습니다. 감사합니다. –

+0

그게 원하는 결과입니까? – Strawberry

답변

0

후 필터가 있어야합니다. 쿼리는 모든 결과를 얻은 다음이를 기반으로 필터링합니다. GROUP BY는 그룹을 기반으로 행을 압축하여 각 세트의 첫 번째 항목을 제공합니다. 플레이어 1은 레이스 1의 첫 번째 엔트리이므로 HAVING에 의해 처리되는 결과입니다. 그런 다음 해당 시간이 그룹 결과의 MIN (시간)과 같지 않기 때문에 필터링됩니다.

게시 한 다른 항목이 하위 쿼리를 사용하는 이유입니다. 내 개인적인 취향은 첫 번째 예제에 대한, 나에게 그것은 약간 읽기 쉽습니다. 성능이 현명해야합니다.

where 절에서 하위 쿼리를 사용하지 않는 것은 좋지 않지만, JOIN을 사용하여 동일한 결과를 얻을 수있을 때 주로 유효합니다. 다른 시간에는 JOIN으로 결과를 얻을 수 없으며 하위 쿼리가 필요합니다.