Rails:4.1.2
数据库:PostgreSQL
对于我的一个查询,我使用的是textacular gem和Active Record中的方法。如何使用" OR"链接以下一些查询?而不是" AND":
people = People.where(status: status_approved).fuzzy_search(first_name: "Test").where("last_name LIKE ?", "Test")
我想将最后两个范围(fuzzy_search
和where
之后)与" OR"连在一起。而不是" AND。"所以我想检索所有被批准的人(其名字与&#34相似;测试"或其姓氏包含"测试")。我已经挣扎了很长一段时间,所以任何帮助都会非常感激!
答案 0 :(得分:0)
我深入研究fuzzy_search并发现它将被翻译成类似的东西:
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')
如果您需要订单,请在加入2个条件后指定您希望订单的内容。
答案 1 :(得分:0)
几天后,我想出了解决方案!这就是我的所作所为:
这是我想与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查询。我也取代了" AND"将最后两个条件与" OR":
连接起来# 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
个对象,通常会返回,所以我无法在此数组上使用where
等ActiveRecord查询方法。使用ID,我们可以执行另一个查询来获取CollectionProxy
对象。但是,有一个问题:如果我们只是简单地运行People.where(id: people_ids)
,那么ID的顺序将不会被保留,因此我们所做的所有相关性排名都是无用的。
幸运的是,有一个名为order_as_specified的好宝石,它允许我们按照ID的特定顺序检索所有People
个对象。虽然宝石可以使用,但我并没有使用它,而是编写了一小段代码来制作可以保留订单的条件。
order_by = people_ids.map { |id| "people.id='#{id}' DESC" }.join(", ")
如果我们的people_ids
数组为[1, 12, 3]
,则会创建以下ORDER语句:
"people.id='1' DESC, people.id='12' DESC, people.id='3' DESC"
我从this comment了解到以这种方式编写ORDER语句会保留顺序。
现在,剩下的就是从ActiveRecord中检索People
个对象,确保指定顺序。
people = People.where(id: people_ids).order(order_by)
就这样做了!我并不担心删除任何重复的ID,因为ActiveRecord会在您运行where
命令时自动执行此操作。
据我所知,这段代码不是非常便携,如果修改了people
表的任何列,则需要进行一些更改,但是它运行正常并且根据控制台似乎只执行一个查询