使用ILIKE查询时PostgreSQL优先级

时间:2011-07-31 00:36:06

标签: ruby-on-rails ruby postgresql

两个灯具:

one:
  firstname: John
  lastname: Doe
  user_id: 1

two:
  firstname: Jane
  lastname: Doe
  user_id: 1

在我的单元测试中,我有以下内容:

 test "Searching for a contact gets the right person" do
    search = Contact.search("John")
    assert_equal 1, search.count

    search = Contact.search("Doe")
    assert_equal 2, search.count

    search = Contact.search("John Doe")
    assert_equal 1, search.count

    search = Contact.search("John ")
    assert_equal 1, search.count

    search = Contact.search("Doe John")
    assert_equal 1, search.count
  end

...最后我调用搜索方法的模型如下:

  def self.search(search)
    # Check if the search query has more than one word
    search_split = search.split(" ")
    if search_split.count > 1
      # User must be searching for a first and last name
      first_word = '%' + search_split[0] + '%'
      second_word = '%' + search_split[1] + '%'
      conditions = "
        firstname ILIKE ? OR lastname ILIKE ? 
        AND 
        firstname ILIKE ? OR lastname ILIKE ?", 
        first_word, first_word, second_word, second_word
      where(conditions)
    else
      # Just searching for a first OR last name
      # Strip any whitespace
      str = search_split[0]
      query = '%' + str + '%'
      conditions = "firstname ILIKE ? OR lastname ILIKE ?", query, query
      where(conditions)
    end
  end

除了对“John Doe”进行测试的测试外,所有测试都通过。它实际上也最终拉了“Jane Doe”。

我认为在邻接的AND之前调用两个OR有一些优先级问题,但它是否能理解我想要完成的事情?

我还没到我正在重构的那一刻;只是想要变绿,这样我才能继续前进。感谢您提前提供任何帮助!

1 个答案:

答案 0 :(得分:3)

您需要进行一些重组才能获得您所追求的逻辑:

conditions = "
  (firstname ILIKE ? AND lastname ILIKE ?)
  OR
  (firstname ILIKE ? AND lastname ILIKE ?)",
  first_word, second_word, second_word, first_word

当你打电话时,那应该与“John Doe”和“Doe John”匹配,而不是“Jane Doe”:

Contact.search('Jo Do')

你实际上并不需要括号,因为布尔代数中的AND has a higher precedence than OR(以及SQL的逻辑是based on Boolean Algebra)但是没有充分的理由不包括它们。