2013-05-01 4 views
0

나는 모델 has_many user_entitlements을 가지고있다. 미리보기 특성과 사용자 권한이없는 모든 사용자를 얻고 싶습니다.레일 고급 SQL 쿼리

내 코드 현재 : 이것은 모든 사용자를 반복하고 모든 사용자 권한이있는 경우보고있다

User.where("preview is not null").keep_if {|user| user.user_entitlements.empty?} 

.

더 효율적으로 만들고 각 사용자를 거치지 않고 SQL에서이 작업을 수행 할 수있는 방법이 있습니까?

답변

1

Arel을 사용하여 NOT EXISTS을 활용하는 쿼리를 작성할 수 있습니다.

user_arel = User.arel_table 
ue_arel = UserEntitlement.arel_table 
User.where("preview is not null").where(
    UserEntitlement.where(ue_arel[:user_id].eq(user_arel[:id])).exists.not 
) 

나는 UserEntitlementuser_id 열을 포함하여 스키마에 대한 가정을하고있다.

+0

Awesome- 당신을 감사합니다! – BC00

1

, 당신은 다음 NULL을 확인 조인 LEFT를 강제로 includes를 사용하더라도 간단 :

User.includes(:user_entitlements). 
    where("users.preview IS NOT NULL AND user_entitlements.id IS NULL") 
+0

큰 데이터 세트가있는 경우 'LEFT JOIN'보다 'NOT EXISTS'로 더 나은 성능을 보게됩니다. 출처 : http://explainextended.com/2009/09/15/not-in-vs-not-exists-vs-left-join-is-null-sql-server/ EDIT : 당신이 더 나은 성능을 보임을 분명히하고, 아래의 PinnyM의 의견을 고려하십시오. –

+1

@DanReedy는 DBMS 및 버전에 따라 달라집니다. 쿼리 최적화 프로그램 만이 특정 쿼리 및 분석을 얼마나 효율적으로 수행 할 수 있는지 결정할 수 있습니다. 연결된 문서는 3.5 년 전이었으며 SQL Server와 관련이 있습니다. MySQL (또는 SQL Server)의 현재 버전이이 점에서 더 나은지 확실하지 않지만 결정되어야합니다. – PinnyM

+0

@ DanReedy, 나는 당신의 접근 방식을 선호하지만, ActiveRecord는이 지저분한 것을 수동으로 작성합니다. 너무 나쁘다면 이것은 일반적인 행동으로 이것을 기본 행동으로 추가하는 보석이 아닙니다. 언젠가는... – PinnyM