ruby-on-rails 从列值包含在字符串中的表中选择记录(带有ActiveRecord的MySQL)

xvw2m8pv  于 2023-01-14  发布在  Ruby
关注(0)|答案(1)|浏览(98)

假设我有一个名为books的表,表中有一个名为keyword的列,还有一个名为words的字符串。
我想从books中选择所有记录,其中keyword列包含在words中。我可以直接在mysql中使用LIKE来完成这一操作。如果有人能给予我语法的话,我正在尝试将其转换为一个针对rails应用的ActiveRecord查询。
棘手的是,我希望查找列值包含在字符串中的记录,而不是相反。与此问题非常相似,只是需要将其转换为ActiveRecord.SQL - Query to find if a string contains part of the value in Column
下面是我正在尝试翻译的一个有效的sql查询。
SELECT * FROM books WHERE "new science fiction" LIKE CONCAT('%',keyword,'%');
在上面的例子中,“new science fiction”是字符串words
假设我有3个book记录。book1有关键字“science”,book2有关键字“fiction”,book3有关键字“other”。我上面的查询将返回记录book1和book2。因为“science”和“fiction”包含在words字符串“new science fiction”中。
我的SQL查询可以工作,但我不知道如何在ActiveRecord中使用Book.where语句。

9w11ddsr

9w11ddsr1#

我觉得你最好的选择是:

Book.where(keyword: words.split)

这将导致

SELECT * FROM books WHERE books.keyword IN ('new', 'science', 'fiction')

这将返回相同的记录。

注意IN()可能区分大小写,具体取决于您的RDBMS。要避免这种情况,我们可以将上面的内容更改为

Book.where(Book.arel_table[:keyword].lower.in(words.downcase.split))

这将导致

SELECT * FROM books WHERE LOWER(books.keyword) IN ('new', 'science', 'fiction')

如果你真的想去与你现在有它的方式,我们可以一起破解如下:

Book.where(
  Arel::Nodes::UnaryOperation.new(nil,Arel::Nodes.build_quoted(words))
    .matches(
      Arel::Nodes::NamedFunction.new(
       'CONCAT', 
       [Arel.sql("'%'"),Book.arel_table[:keyword],Arel.sql("'%'")])
))

这将产生所需的SQL,同时仍然利用Arel和连接适配器提供的转义。
这里区分大小写不是问题,因为Arel::Predications#matches默认使用case_sensitive = false,这意味着Postgres将使用ILIKE而不是LIKE

相关问题