如何在 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) 中的变量编写查询的主要内容,如果未能解决你的问题,请参考以下文章

如何在 EXECUTE IMMEDIATE 中使用动态 where 子句

如何在 WHERE 子句中使用条件不同的列?

如何在 WHERE 子句中使用 IF ELSE

如何在 WHERE 子句(MySQL)中使用 VIEW?

如何在 where 子句中使用临时列

如何在 WHERE 子句中使用混合文本和日期字段?