2012-02-10 2 views
1

단일 레코드가 다른 테이블 (ID와 has_many 문으로 링크 됨)에 여러 레코드가 있어야하는 검색을 만들려고합니다. 결과로 포함됩니다.Ruby on Rails : 여러 행이 다른 테이블에 있어야하는 테이블 검색

나는 테이블이 users, skill_lists, skill_maps입니다.

사용자는 skill_maps 테이블의 단일 항목을 통해 개별 기술에 매핑됩니다. 많은 사용자가 단일 기술을 공유 할 수 있으며 단일 사용자는 skill_maps 테이블에서 여러 항목을 통해 많은 기술을 보유 할 수 있습니다.

User_id | Skill_list_id 
2  | 9 
2  | 15 
3  | 9 

사용자 2는 기술 9 3 내가 기술의 집합이 모든 사용자의 해시를 반환하는 검색을 만들려고 해요 9

유일한 기술을 가지고 15
사용자가 있습니다. 필요한 집합 skill_ids은 params에 배열로 나타납니다.

skill_selection_user_ids = SkillMap.find_all_by_skill_list_id(params[:skill_ids]).map(&:user_id) 

@results = User.find(:all, :conditions => {:id => skill_selection_user_ids}) 

문제는이 아닌 그들 모두가 사용자가 이러한 기술 중 하나를 모든 사용자를 반환한다는 것입니다 :

여기 내가 사용하는 코드입니다.

또한, 내 사용자 테이블은 skill_lists 테이블 :through => :skill_maps에 연결되고, 그 반대로 그래서 내가이 진짜 초보자 질문입니다 확신 나는에 완전히 새로운 해요 ...

@user.skill_list 등을 호출 할 수 레일 (및 프로그래밍). 검색을 시도했지만 해결책을 찾지 못했습니다. 나는 단 하나 수색 기간에있는 문제를 설명하는 방법을 모릅니다.

답변

1

개인적으로 ActiveRecord의 쿼리 인터페이스를 사용하여이를 수행하는 방법을 알지 못합니다. 가장 쉬운 것은 각각의 기술을 가진 사용자의 목록을 검색 한 다음 아마도 설정하여, 해당 목록의 교차점을하는 것입니다 : (가능성이) 더 높은 성능을 위해

require 'set' 

skills = [5, 10, 19] # for example 
user_ids = skills.map { |s| Set.new(SkillMap.find_all_by_skill_list_id(s).map(&:user_id)) }.reduce(:&) 
users = User.where(:id => user_ids.to_a) 

을, 당신은 "롤 - 수 귀하 자신의 "SQL 및 DB 엔진이 작업을 할 수 있습니다. 여기에 고성능이 필요한 경우 몇 가지 SQL을 생각해 낼 수 있습니다. (또는 다른 사람이 할 수있는 경우이 대답을 편집하십시오!)

그런데 skill_maps 테이블이 매우 커질지라도 좋은 성능을 얻으려면 skill_maps.skill_list_id에 인덱스를 두어야합니다. ActiveMigration 설명서를 참조하십시오. http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

+0

작동합니다! 정말 고맙습니다! 이 새 목록으로 사용자 테이블을 검색하려면 먼저 .to_a를 추가해야했습니다. 여기 내 마지막 코드는 다음과 같습니다. 'skill_selection_user_ids = params [: teach_skill_ids] .map {| s | 012 : 사용자 ID => {: id => skill_selection_user_ids.to_a} .resource = User.find (: all, : conditions => {: id => 스킬 _ 선택 _ 사용자 _) ' 다시 한번 감사드립니다 !!! – joshblour

+0

할 수 있습니다 :'@results = User.find skill_selection_user_ids.entries'. '항목'은 집합을 단순히 '찾기'로 피드하는 배열로 변환합니다. – dynex

+0

도 그 덕분에 @dynex! – joshblour

1

아마도 사용자 ID를 얻기 위해 일부 사용자 지정 SQL을 사용해야 할 것입니다. 비슷한 HABTM 관계에서이 쿼리를 테스트 한 결과 작동하는 것으로 보입니다.

SELECT DISTINCT(user_id) FROM skill_maps AS t1 WHERE (SELECT COUNT(skill_list_id) FROM skill_maps AS t2 WHERE t2.user_id = t1.user_id AND t2.skill_list_id IN (1,2,3)) = 3 

트릭은 하위 쿼리에 있습니다. 외부 쿼리의 각 행에 대해, 그것은 당신이 관심있는 기술의 어떤 일치하는 행에 대한 기록의 수를 발견한다. 그 다음은을 계산 이 기술의 일치 여부를 확인 당신은 관심이 있습니다. 일치하는 것이 있으면, 사용자는 당신이 검색 한 모든 기술을 소유하고 있어야합니다.

당신은 find_by_sql를 사용하여 레일이를 실행할 수 있습니다 :

sql = 'SELECT DISTINCT(user_id) FROM skill_maps AS t1 WHERE (SELECT COUNT(skill_list_id) FROM skill_maps AS t2 WHERE t2.user_id = t1.user_id AND t2.skill_list_id IN (?)) = ?' 
skill_ids = params[:skill_ids] 
user_ids = SkillMap.find_by_sql([sql, skill_ids, skill_ids.size]) 

죄송 테이블 및 열 이름이 정확히 바로 아니지만, 희망이 야구장에있는 경우.