복붙노트

[RUBY-ON-RAILS] 어떻게 체인 범위 쿼리에 대한 OR 대신 AND?

RUBY-ON-RAILS

어떻게 체인 범위 쿼리에 대한 OR 대신 AND?

나는 Rails3, 액티브을 사용하고 있습니다

그냥 내가 AND 대신에 범위 OR 문을 체인 수있는 방법을 궁금해.

EG

Person.where(:name => "John").where(:lastname => "Smith")

일반적으로 반환한다 :

name = 'John' AND lastname = 'Smith'

하지만 내가 좋아하는 것 :

`name = 'John' OR lastname = 'Smith'

해결법

  1. ==============================

    1.당신은 할 것

    당신은 할 것

    Person.where('name=? OR lastname=?', 'John', 'Smith')
    

    지금, (일부 타사 보석을 사용하지 않고있다) 새로운 AR3 구문에 의해 다른 또는 지원이되지 않습니다.

  2. ==============================

    2.이 풀의 요청에 따라, 레일 (5)는 이제 쿼리를 체인에 대해 다음 구문을 지원합니다 :

    이 풀의 요청에 따라, 레일 (5)는 이제 쿼리를 체인에 대해 다음 구문을 지원합니다 :

    Post.where(id: 1).or(Post.where(id: 2))
    

    이 보석을 통해 레일 4.2에 기능의 백 포트도 있습니다.

  3. ==============================

    3.사용 ARel

    사용 ARel

    t = Person.arel_table
    
    results = Person.where(
      t[:name].eq("John").
      or(t[:lastname].eq("Smith"))
    )
    
  4. ==============================

    4.그냥 도움말을 동일한 열 또는 쿼리의 배열 구문을 게시 개 친구.

    그냥 도움말을 동일한 열 또는 쿼리의 배열 구문을 게시 개 친구.

    Person.where(name: ["John", "Steve"])
    
  5. ==============================

    5.Rails4 업데이트

    Rails4 업데이트

    더 3 자 보석을 필요로하지 않는다

    a = Person.where(name: "John") # or any scope 
    b = Person.where(lastname: "Smith") # or any scope 
    Person.where([a, b].map{|s| s.arel.constraints.reduce(:and) }.reduce(:or))\
      .tap {|sc| sc.bind_values = [a, b].map(&:bind_values) }
    

    올드 대답

    더 3 자 보석을 필요로하지 않는다

    Person.where(
        Person.where(:name => "John").where(:lastname => "Smith")
          .where_values.reduce(:or)
    )
    
  6. ==============================

    6.또한 SQL 물건과 코드를 혼합하지 MetaWhere 보석을 사용할 수 있습니다 :

    또한 SQL 물건과 코드를 혼합하지 MetaWhere 보석을 사용할 수 있습니다 :

    Person.where((:name => "John") | (:lastname => "Smith"))
    
  7. ==============================

    7.https://github.com/rails/rails/pull/9052 : 레일이 점을 얻기 위해 기존 풀 요청이 같은 경우 사람이 일에 업데이트 된 대답을 찾고, 그것은 보인다.

    https://github.com/rails/rails/pull/9052 : 레일이 점을 얻기 위해 기존 풀 요청이 같은 경우 사람이 일에 업데이트 된 대답을 찾고, 그것은 보인다.

    액티브 (https://gist.github.com/j-mcnally/250eaaceef234dd8971b)는 다음을 수행 할 수 있습니다위한 @ J-맥널리의 원숭이 패치에 감사 :

    Person.where(name: 'John').or.where(last_name: 'Smith').all
    

    더욱 중요한 것은 체인 능력과 또는 스코프입니다 :

    scope :first_or_last_name, ->(name) { where(name: name.split(' ').first).or.where(last_name: name.split(' ').last) }
    scope :parent_last_name, ->(name) { includes(:parents).where(last_name: name) }
    

    그럼 당신은 부모 성을 가진 성이나 이름 또는 모든 사람을 찾을 수 있습니다

    Person.first_or_last_name('John Smith').or.parent_last_name('Smith')
    

    이것의 사용하지 최고의 예는 있었으나 결국 질문을 맞게하려고합니다.

  8. ==============================

    8.나 (4.2.5 레일)의 경우에만 다음과 같이 작동합니다 :

    나 (4.2.5 레일)의 경우에만 다음과 같이 작동합니다 :

    { where("name = ? or name = ?", a, b) }
    
  9. ==============================

    9.당신은 3.0 레일을 사용하는 경우이 MetaWhere에 대한 좋은 후보가 될 것이지만, 레일 3.1 일을하지 않습니다. 대신 squeel을 시도 할 수 있습니다. 그것은 동일한 저자에 의해 만들어졌다. 여기가 OR 기반의 체인을 수행 할 것 어떻게 것 :

    당신은 3.0 레일을 사용하는 경우이 MetaWhere에 대한 좋은 후보가 될 것이지만, 레일 3.1 일을하지 않습니다. 대신 squeel을 시도 할 수 있습니다. 그것은 동일한 저자에 의해 만들어졌다. 여기가 OR 기반의 체인을 수행 할 것 어떻게 것 :

    Person.where{(name == "John") | (lastname == "Smith")}
    

    당신은 많은 다른 멋진 것들 사이에, 믹스 앤 매치 AND / OR 수 있습니다.

  10. ==============================

    10.레일의 업데이트 된 버전 / 액티브는 기본적으로이 구문을 지원할 수 있습니다. 그것은 비슷한에 보일 것입니다 :

    레일의 업데이트 된 버전 / 액티브는 기본적으로이 구문을 지원할 수 있습니다. 그것은 비슷한에 보일 것입니다 :

    Foo.where(foo: 'bar').or.where(bar: 'bar')
    

    이 풀 https://github.com/rails/rails/pull/9052 요청에 명시된 바와

    지금은 단순히 다음과 고집하는 것은 잘 작동합니다 :

    Foo.where('foo= ? OR bar= ?', 'bar', 'bar')
    
  11. ==============================

    11.레일 4 + 범위 + Arel

    레일 4 + 범위 + Arel

    class Creature < ActiveRecord::Base
        scope :is_good_pet, -> {
            where(
                arel_table[:is_cat].eq(true)
                .or(arel_table[:is_dog].eq(true))
                .or(arel_table[:eats_children].eq(false))
            )
        }
    end
    

    내가 불러야과 행운와라는 이름의 범위를 체인했지만,이 설정된 부울 아무것도를 찾는 일했다. SQL처럼 생성

    SELECT 'CREATURES'.* FROM 'CREATURES' WHERE ((('CREATURES'.'is_cat' = 1 OR 'CREATURES'.'is_dog' = 1) OR 'CREATURES'.'eats_children' = 0))
    
  12. ==============================

    12.4 레일

    4 레일

    scope :combined_scope, -> { where("name = ? or name = ?", 'a', 'b') }
    
  13. ==============================

    13.당신이 (즉, 두 개의 범위를 결합하려는)을 "또는"문을 포함하도록 수동으로 where 절을 쓸 수없는 경우에는 노동 조합을 사용할 수 있습니다 :

    당신이 (즉, 두 개의 범위를 결합하려는)을 "또는"문을 포함하도록 수동으로 where 절을 쓸 수없는 경우에는 노동 조합을 사용할 수 있습니다 :

    Model.find_by_sql("#{Model.scope1.to_sql} UNION #{Model.scope2.to_sql}")
    

    (출처 : 액티브 쿼리 연합)

    이 중 쿼리와 일치하는 모든 레코드를 반환 것입니다. 그러나,이 배열이 아닌 arel를 반환합니다. https://gist.github.com/j-mcnally/250eaaceef234dd8971b : 당신이 정말 arel을 반환하려는 경우, 당신은이 요점을 체크 아웃.

    이는 당신이 원숭이 패치 레일을 신경 쓰지 않는 한, 일을 할 것입니다.

  14. ==============================

    14.당신이 (명시 적으로 전체 데이터 세트 작업 대신) 범위를 제공하기 위해 찾고 있다면 여기에 당신이 레일 (5)와 함께해야 할 일이다 :

    당신이 (명시 적으로 전체 데이터 세트 작업 대신) 범위를 제공하기 위해 찾고 있다면 여기에 당신이 레일 (5)와 함께해야 할 일이다 :

    scope :john_or_smith, -> { where(name: "John").or(where(lastname: "Smith")) }
    

    또는:

    def self.john_or_smith
      where(name: "John").or(where(lastname: "Smith"))
    end
    
  15. ==============================

    15.또한이 관련 질문을 참조하십시오 여기, 여기와 여기에

    또한이 관련 질문을 참조하십시오 여기, 여기와 여기에

    레일 4은이 문서와이 원래의 답변에 따라

    Person
      .unscoped # See the caution note below. Maybe you want default scope here, in which case just remove this line.
      .where( # Begin a where clause
        where(:name => "John").where(:lastname => "Smith")  # join the scopes to be OR'd
        .where_values  # get an array of arel where clause conditions based on the chain thus far
        .inject(:or)  # inject the OR operator into the arels 
        # ^^ Inject may not work in Rails3. But this should work instead:
        .joins(" OR ")
        # ^^ Remember to only use .inject or .joins, not both
      )  # Resurface the arels inside the overarching query
    

    말에 기사의주의 사항을 참고 :

  16. ==============================

    16.squeel 보석이 작업을 수행 할 수있는 매우 쉬운 방법을 제공합니다 (전 @의 coloradoblue의 방법 등이 내가 사용하는 뭔가) :

    squeel 보석이 작업을 수행 할 수있는 매우 쉬운 방법을 제공합니다 (전 @의 coloradoblue의 방법 등이 내가 사용하는 뭔가) :

    names = ["Kroger", "Walmart", "Target", "Aldi"]
    matching_stores = Grocery.where{name.like_any(names)}
    
  17. ==============================

    17.원래의 질문에 대한 대답 그래서, 당신은 대신에 '나'로 범위를 가입 '과'수는 "아니오 당신이 할 수없는"것으로 보인다. 하지만 당신은 코드에게 일을 완전히 다른 범위 또는 쿼리를 손으로, 또는 액티브 예에서 다른 프레임 워크를 사용할 수 있습니다 MetaWhere 또는 Squeel. 내 경우에는 유용하지 않음

    원래의 질문에 대한 대답 그래서, 당신은 대신에 '나'로 범위를 가입 '과'수는 "아니오 당신이 할 수없는"것으로 보인다. 하지만 당신은 코드에게 일을 완전히 다른 범위 또는 쿼리를 손으로, 또는 액티브 예에서 다른 프레임 워크를 사용할 수 있습니다 MetaWhere 또는 Squeel. 내 경우에는 유용하지 않음

    나는 '조금 더 선택 이상하지, 그것은 깨끗한 노조의 난장판을 만드는 ASC에 의해 순서를 포함 pg_search에 의해 생성 된 범위를, OR 처리하고 있습니다. 나는 pg_search에서 할 수없는 물건을 수행하는 손수 범위로에 '또는'합니다. 그래서 이런 식으로해야했다했습니다.

    Product.find_by_sql("(#{Product.code_starts_with('Tom').to_sql}) union (#{Product.name_starts_with('Tom').to_sql})")
    

    즉 SQL로 범위를 설정,이를 함께, 각각의 주위에 노동 조합을 괄호를 넣고 find_by_sql 생성 된 SQL을 사용하여. 그것은 비트 쓰레기지만,이 작업을 수행합니다.

    pg_search, 나는 그런 식으로 그것을 할 싶습니다하지만 '이름'필드는 hstore, pg_search 수없는 핸들입니다 "[: 코드 : 이름]에 대해"아니, 내가 사용할 수 있습니다 말하지 않는다 아직. 이름으로 범위가 있어야한다 그래서 손으로 제작하고 pg_search 범위와 UNION을.

  18. ==============================

    18.이것은 매우 편리한 방법이며 레일 5에서 잘 작동합니다 :

    이것은 매우 편리한 방법이며 레일 5에서 잘 작동합니다 :

    Transaction
      .where(transaction_type: ["Create", "Correspond"])
      .or(
        Transaction.where(
          transaction_type: "Status",
          field: "Status",
          newvalue: ["resolved", "deleted"]
        )
      )
      .or(
        Transaction.where(transaction_type: "Set", field: "Queue")
      )
    
  19. ==============================

    19.

    names = ["tim", "tom", "bob", "alex"]
    sql_string = names.map { |t| "name = '#{t}'" }.join(" OR ")
    @people = People.where(sql_string)
    
  20. from https://stackoverflow.com/questions/3684311/how-to-chain-scope-queries-with-or-instead-of-and by cc-by-sa and MIT license