2009-12-04 6 views
2

나는 (다른 것들 중에서) 이름과 계급을 가진 테이블을 가지고있다. 모든 고유 한 이름 집합을 반환하고 싶지만 반환 된 각 이름에 대해 가장 높은 순위의 행을 선택하고 싶습니다. 이 두 개의 중첩 SELECT 문에 간단하다 :ActiveRecord 중첩 SELECT - 수동 SQL없이 수행 할 수 있습니까?

SELECT * FROM (SELECT * FROM foo ORDER BY rank DESC) AS ordered GROUP BY name 

MySQL은 먼저 항상 가장 높은 순위 하나가 될 것입니다 (때문에 BY 이전 ORDER의) 각각의 이름에 대해 "공격"합니다.

이제 ActiveRecord를 사용하여이 테이블에 연결하려면 약간의 손실이 있습니다. 위의 내용을 find_by_sql에 넣을 수는 있지만 더러운 느낌입니다. 나는

result = foo.all 
result.delete_if do |item| 
    isOutranked = false 
    result.each do |row| 
    if (row.name == item.name) and (row.rank > item.rank) then isOutranked = true 
    end 
    isOutranked 
end 

내가 를 작동 생각처럼 뭔가를 시도했지만 여전히 같은 더 나은 방법이있을한다고 느낀다. ActiveRecord 속임수 또는보다 우아한 배열 조작을 통해 해결하면 환영할만한 것입니다!

답변

2

MySQL은 각 이름에 대해 첫 번째 "히트"를 취합니다. (이전 ORDER BY 때문에) 항상 최상위 순위입니다. 당신이 그룹의 맨 위의 행을 반환하는 데 사용하는

쿼리은 보장 하지입니다. 이는 구현의 유일한 우연이며, 변경 될 수 있습니다. 이것에 의존하지 마십시오.

StackOverflow에 자주 게시되는 "greatest-n-per-group"문제를 해결하려고합니다. 같은 일을

SELECT t1.* 
FROM foo AS t1 
LEFT OUTER JOIN foo AS t2 
ON (t1.name = t2.name AND t1.rank < t2.rank) 
WHERE t2.name IS NULL; 

대안 : 여기에보다 확실하게 해답을 얻을 수 쿼리는

SELECT * 
FROM foo AS t1 
WHERE NOT EXISTS 
    (SELECT * FROM foo AS t2 
    WHERE t1.name = t2.name AND t1.rank < t2.rank); 

난 그냥 find_by_sql에 위 던질 수 있지만, 그건 그냥 더러운 느낌.

ActiveRecord는 특정 종류의 쿼리에 매우 편리하지만 ActiveRecord를 사용하는 모든 데이터베이스 쿼리를 해결할 수는 없습니다. 이 개념을 빠르면 빠를수록 작업이 완료되고 성공할 수 있습니다. SQL은 당신을 물지 않을 것입니다.

관련 문제