簡體   English   中英

活動記錄-帶有OR的鏈式查詢

[英]Active Record - Chain Queries with OR

滑軌:4.1.2

數據庫:PostgreSQL

對於我的查詢之一,我正在使用textacular gem和Active Record中的方法。 如何將以下某些查詢鏈接為“或”而不是“與”:

people = People.where(status: status_approved).fuzzy_search(first_name: "Test").where("last_name LIKE ?", "Test")

我想用“ OR”而不是“ AND”將最后兩個范圍( fuzzy_search及其fuzzy_searchwhere )鏈接在一起。 因此,我想檢索所有已批准AND(其名字類似於“ Test”或其姓氏包含“ Test”的人)。 我已經為此苦苦掙扎了很長時間了,因此任何幫助將不勝感激!

我深入研究了模糊搜索,發現它將被翻譯成類似以下內容的內容:

SELECT "people".*, COALESCE(similarity("people"."first_name", 'test'), 0) AS "rankxxx" 
FROM "people" 
WHERE (("people"."first_name" % 'abc'))  
ORDER BY "rankxxx" DESC

也就是說,如果您不關心保留順序,它將僅按WHERE (("people"."first_name" % 'abc'))過濾結果

知道了這一點,現在您可以簡單地編寫具有類似功能的查詢:

People.where(status: status_approved)
      .where('(first_name % :key) OR (last_name LIKE :key)', key: 'Test')

如果您想訂購,請指定加入兩個條件后訂購的商品。

幾天后,我想出了解決方案! 這是我所做的:

這是我想與OR鏈接在一起的查詢:

people = People.where(status: status_approved).fuzzy_search(first_name: "Test").where("last_name LIKE ?", "Test")

正如Hoang Phan所建議的那樣,當您在控制台中查看時,將產生以下SQL:

SELECT "people".*, COALESCE(similarity("people"."first_name", 'test'), 0) AS "rank69146689305952314"
FROM "people"
WHERE "people"."status" = 1 AND (("people"."first_name" % 'Test')) AND (last_name LIKE 'Test')  ORDER BY "rank69146689305952314" DESC

然后,我挖出了織紋寶石,並發現了等級的產生方式。 我在textacular.rb文件中找到了它,然后使用它編寫了SQL查詢。 我還用“ OR”替換了連接最后兩個條件的“ AND”:

# Generate a random number for the ordering
rank = rand(100000000000000000).to_s

# Create the SQL query
sql_query = "SELECT people.*, COALESCE(similarity(people.first_name, :query), 0)" + 
            " AS rank#{rank} FROM people" +
            " WHERE (people.status = :status AND" +
            " ((people.first_name % :query) OR (last_name LIKE :query_like)))" + 
            " ORDER BY rank#{rank} DESC"

在引用表和字段時,我將SQL查詢中的所有引號都刪除了,因為當我將它們保留在其中時,即使使用單引號,它也會給我錯誤消息。

然后,我使用find_by_sql方法檢索數組中的People對象ID。 符號( :status:query:query_like )用於防止SQL注入,因此我相應地設置了它們的值:

# Retrieve all the IDs of People who are approved and whose first name and last name match the search query.
# The IDs are sorted in order of most relevant to the search query.
people_ids = People.find_by_sql([sql_query, query: "Test", query_like: "%Test%", status: 1]).map(&:id)

我得到ID而不是數組中的People對象,因為find_by_sql返回的是Array對象,而不是通常返回的CollectionProxy對象,因此我無法使用ActiveRecord查詢方法,例如該數組上的where 使用這些ID,我們可以執行另一個查詢來獲取CollectionProxy對象。 但是,存在一個問題:如果僅運行People.where(id: people_ids) ,則ID的順序將不會保留,因此我們所做的所有相關性排名都沒有用。

幸運的是,有一個名為order_as_specified的漂亮gem,它使我們可以按ID的特定順序檢索所有People對象。 盡管該gem可以工作,但我沒有使用它,而是編寫了一小段代碼來編寫可以保留訂單的條件。

order_by = people_ids.map { |id| "people.id='#{id}' DESC" }.join(", ")

如果我們的people_ids數組為[1, 12, 3] people_ids [1, 12, 3] ,它將創建以下ORDER語句:

"people.id='1' DESC, people.id='12' DESC, people.id='3' DESC"

我從此注釋中學到,以這種方式編寫ORDER語句將保留順序。

現在,剩下的就是從ActiveRecord檢索People對象,並確保指定順序。

people = People.where(id: people_ids).order(order_by)

做到了! 我不必擔心刪除任何重復的ID,因為ActiveRecord在運行where命令時會自動執行。

我知道這段代碼不是很容易移植,如果修改了people表的任何列,都需要進行一些更改,但是它可以正常工作,並且似乎只能根據控制台執行一個查詢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM