[ruby-on-rails] ActiveRecord / Rails로 NOT IN 쿼리를 표현하는 방법?

Rails 4를 사용하고 있다면 Trung Lê`와 VinniVidiVicci의 답변을 살펴보십시오.

Topic.where.not(forum_id:@forums.map(&:id))

Topic.where(published:true).where.not(forum_id:@forums.map(&:id))

나는 포함되지 않는 쉬운 해결책이 있기를 바라고 있습니다 find_by_sql. 그렇지 않으면 그것이 작동해야한다고 생각합니다.

이것을 참조 하는 이 기사 를 찾았습니다 .

Topic.find(:all, :conditions => { :forum_id => @forums.map(&:id) })

이것은 같은

SELECT * FROM topics WHERE forum_id IN (<@forum ids>)

그와 관련이있는 방법이 있는지 궁금합니다 NOT IN.

SELECT * FROM topics WHERE forum_id NOT IN (<@forum ids>)



답변

레일 4+ :

Article.where.not(title: ['Rails 3', 'Rails 5']) 

레일 3 :

Topic.where('id NOT IN (?)', Array.wrap(actions))

다음 actions과 같은 배열은 어디에 있습니까?[1,2,3,4,5]


답변

참고로 Rails 4에서는 다음 not구문 을 사용할 수 있습니다 .

Article.where.not(title: ['Rails 3', 'Rails 5'])


답변

다음과 같은 것을 시도해 볼 수 있습니다.

Topic.find(:all, :conditions => ['forum_id not in (?)', @forums.map(&:id)])

해야 할 수도 있습니다 @forums.map(&:id).join(','). Rails가 열거 가능한 경우 CSV 목록에 인수를 표시할지 여부를 기억할 수 없습니다.

당신은 또한 이것을 할 수 있습니다 :

# in topic.rb
named_scope :not_in_forums, lambda { |forums| { :conditions => ['forum_id not in (?)', forums.select(&:id).join(',')] }

# in your controller 
Topic.not_in_forums(@forums)


답변

Arel 사용 :

topics=Topic.arel_table
Topic.where(topics[:forum_id].not_in(@forum_ids))

또는 원하는 경우 :

topics=Topic.arel_table
Topic.where(topics[:forum_id].in(@forum_ids).not)

4 번 레일부터

topics=Topic.arel_table
Topic.where.not(topics[:forum_id].in(@forum_ids))

결국 forum_ids가 ID 목록이 아니라 하위 쿼리가되기를 원하지 않으면 주제를 얻기 전에 이와 같은 작업을 수행해야합니다.

@forum_ids = Forum.where(/*whatever conditions are desirable*/).select(:id)

이런 식으로 단일 쿼리로 모든 것을 얻을 수 있습니다.

select * from topic
where forum_id in (select id
                   from forum
                   where /*whatever conditions are desirable*/)

또한 결국이 작업을 원하지 않고 오히려 조인이 더 효율적일 수 있습니다.


답변

@Trung Lê 답변을 확장하려면 Rails 4에서 다음을 수행하십시오.

Topic.where.not(forum_id:@forums.map(&:id))

한 걸음 더 나아갈 수 있습니다. 먼저 게시 된 주제 만 필터링 한 다음 원하지 않는 ID 필터링 해야하는 경우 다음 을 수행 할 수 있습니다.

Topic.where(published:true).where.not(forum_id:@forums.map(&:id))

Rails 4는 훨씬 쉬워졌습니다!


답변

@forums비어 있으면 승인 된 솔루션이 실패합니다 . 이 문제를 해결하려면

Topic.find(:all, :conditions => ['forum_id not in (?)', (@forums.empty? ? '' : @forums.map(&:id))])

또는 Rails 3 이상을 사용하는 경우 :

Topic.where( 'forum_id not in (?)', (@forums.empty? ? '' : @forums.map(&:id)) ).all


답변

위의 답변의 대부분은 당신에게 충분하지만, 당신이 많은 술어와 복잡한 조합을 많이하고 있다면 Squeel을 확인하십시오 . 다음과 같은 작업을 수행 할 수 있습니다.

Topic.where{{forum_id.not_in => @forums.map(&:id)}}
Topic.where{forum_id.not_in @forums.map(&:id)}
Topic.where{forum_id << @forums.map(&:id)}