如何在 Ruby 中使用 Where 子句 (PostgreSQL) 中的变量编写查询
Posted
技术标签:
【中文标题】如何在 Ruby 中使用 Where 子句 (PostgreSQL) 中的变量编写查询【英文标题】:How Do I Write A Query In Ruby Using Variables WIthin A Where Clause (PostgreSQL) 【发布时间】:2012-12-17 23:39:12 【问题描述】:这就是我希望在不使用 gem 的情况下实现的目标。我在我的一个视图中有一个搜索功能,我希望允许人们在单个字段中输入名字和姓氏,让我的类方法搜索名字和姓氏并生成一个列表。我目前有以下丑陋的代码,它将在两个字段上进行全文搜索。怜悯我 :) 我是 SQL 和 PostgreSQL 的新手。我只做了基本的查询。
def self.text_search(query)
if query.present?
q1, q2, q3, q4 = query.split(' ')
case
when q4 != nil
where('first_name @@ :q1 OR first_name @@ :q2 OR first_name @@ :q3 OR first_name @@ :q4 OR last_name @@ :q1 OR last_name @@ :q2 OR last_name @@ :q3 OR last_name @@ :q4', q1: q1, q2: q2, q3: q3, q4: q4)
when q3 != nil
where('first_name @@ :q1 OR first_name @@ :q2 OR first_name @@ :q3 OR last_name @@ :q1 OR last_name @@ :q2 OR last_name @@ :q3', q1: q1, q2: q2, q3: q3)
when q2 != nil
where('first_name @@ :q1 OR first_name @@ :q2 OR last_name @@ :q1 OR last_name @@ :q2', q1: q1, q2: q2)
else
where('first_name @@ :q1 OR last_name @@ :q1', q1: q1)
end
else
scoped
end
end
此代码适用于在两个字段中搜索整个单词并生成所有匹配的记录。但是,我想做的是能够搜索以在搜索框中输入的值开头的列。例如,如果有人输入“Pat”,则查询将选择 Pat、Patrick、Patrice、Patricia 等。我确信有更好的方法来编写我包含的代码,我可以在其中列出我想要的所有值检查 first_name 和 last_name(或者至少我希望有)。
我今天一直在做很多关于这个的网络搜索。我发现了很多关于这方面的各个方面的信息。我看到了如何使用变量创建正则表达式。这对我来说很明显。我的问题是弄清楚如何将这些信息传递到我的 where 子句中。例如,我为所有四个字段尝试了以下代码。
qr1 = /^#q1/
然后我做了一个类似的 where 子句,我检查了所有四个值的 first_name 和 last_name。我的查询没有返回任何行。
where ('first_name ~ :qr1', qr1: qr1)
我还看到了有关检查子字符串与数组进行比较的解决方案。我在该解决方案中看到的问题是,您必须知道输入的值需要多长时间才能成功。这是一个带有示例的 Stack Overflow 帖子:
Select where first letter in a range ( PostgreSQL )
我还观看了 RailsCasts #343 (Pro),其中讨论了 to_tsvector 和 plainto_tsquery,但坦率地说,我迷路了。也许这是我的答案,但我可以肯定需要一些帮助。这对我来说就像泥巴一样清晰。
【问题讨论】:
为什么不想使用 gem 呢?有很多库可以让这项任务变得更容易。 例如,github.com/ernie/squeel gem。 你试过了吗? github.com/Casecommons/pg_search 在我写了这个问题并给出了更多的想法之后,我决定尝试实现 pg_search。我提到的 RailsCasts 中讨论了那个宝石,但当时它很清楚。可能是我看的时候想太多了。我决定再检查一次。我去了 github,看到了如何选择我认为 :prefix 来做开始的功能。这次我成功地实施了它。非常感谢您的投入。我将保存到 squeel 的链接作为参考。 【参考方案1】:def self.text_search(query)
if query.present?
arr = query.split(' ').map |q| "%#q"
where('first_name ~~* ANY(ARRAY[:arr]) OR last_name ~~* ANY(ARRAY[:arr])', arr: arr)
else
scoped
end
end
【讨论】:
以上是关于如何在 Ruby 中使用 Where 子句 (PostgreSQL) 中的变量编写查询的主要内容,如果未能解决你的问题,请参考以下文章