【问题标题】:Multiple words in LIKE sql operatorLIKE sql运算符中的多个单词
【发布时间】:2017-09-25 16:04:41
【问题描述】:

我有一个变量 str,其中包含一个类似 The ruby 的字符串,它会根据它找到结果。

User.where('abc LIKE :q OR xyz LIKE :q ', q: "%#{str}%") 

虽然它工作正常,但如果 str 变量包含类似 str = ["The", "ruby"] 的数组,我会卡住该怎么办

我可以运行一个循环,但它会创建多个查询,我不希望这样。可以用相同的代码完成吗?

我知道如果我必须测试多个单词,那么我必须做这样的事情

User.where('abc LIKE :q OR abc LIKE :r OR xyz LIKE :q OR xyz LIKE :r ', q: "%#{str[0]}%", r: "%#{str[1]}%")

例如,我在数组中使用了 2 个值,但实际上它可以是任意长度。

如果我做得对,请告诉我

【问题讨论】:

    标签: mysql ruby-on-rails activerecord


    【解决方案1】:

    正如您最初所想的那样,您可以执行一个循环来创建多个查询。您不需要单独运行查询,但是,您可以使用 or 将它们加入到单个 SQL 语句中:

    examples = ['The Ruby', ['The', 'Ruby']]
    
    examples.each do |search|
      queries = Array(search).map do |search_term|
        User.where('category_title LIKE :q OR title LIKE :q OR description LIKE :q OR tag_list LIKE :q', q: "%#{search_term}%")
      end
    
      statement = queries.reduce do |statement, query|
        statement.or(query)
      end
    
      puts statement.to_sql
    end
    

    它的输出是(当然,清理了一点):

    SELECT "users".* FROM "users"
    WHERE (category_title LIKE '%The Ruby%' OR title LIKE '%The Ruby%'
      OR description LIKE '%The Ruby%' OR tag_list LIKE '%The Ruby%')
    
    SELECT "users".* FROM "users"
    WHERE ((category_title LIKE '%The%' OR title LIKE '%The%' OR
              description LIKE '%The%' OR tag_list LIKE '%The%') OR
           (category_title LIKE '%Ruby%' OR title LIKE '%Ruby%' OR
              description LIKE '%Ruby%' OR tag_list LIKE '%Ruby%'))
    

    【讨论】:

    • 它有效,但有没有办法避免执行多个查询?
    • 这只会执行一个查询,如果对数据库执行了任何操作,我的脚本就会开始对所有内容大喊大叫,因为这些列在我的用户模型上不存在。
    • 对不起,你是对的。我可以看到它只做了一个请求。
    • 你能解释一下它是如何只进行一次查询的吗?我们在循环中使用 User.where 并且不会创建多个查询?
    • TL;DR rails 在需要某些记录之前不会执行查询;在控制台中,这是立即的,因为控制台喜欢显示输出,但在“真实”代码中,这通常位于视图中的某个位置,或者您正在处理记录的任何地方。这和User.where(...).where(...) 是一样的,你可以在不触发查询的情况下调用多个where,所以这只是将中介存储在一个变量中而不是立即链接它
    【解决方案2】:

    很抱歉,如果这个答案被认为有点离题,但是有更有效的方法来查询 OP 所要求的信息,而不是通过暴力破解并将大量 LIKE 查询链接在一起。

    @Raaz,您使用的是哪个数据库引擎?多个标记听起来像是基于 POSIX 正则表达式的查询的一个很好的用例。与一次只搜索 1 个标记的 LIKE 查询相比,使用模式匹配可以让您在单个查询中搜索任意数量的标记,而只需几个 WHERE 子句。

    PostgresMySQL 都可以使用模式进行查询。

    对于 Postgres,它看起来像这个未经证实的代码 sn-p:

    Video.where("category_title SIMILAR TO '%(the|ruby)%'"
    

    另一个假设您使用 Postgres 的选项是使用 pg_search gem 并在您的数据库上执行 multisearchable 搜索。您可以一次查询这四个字段,数据库将完成所有繁重的工作。同样,这假设您使用的是 Postgres 数据库。

    【讨论】:

    • 对不起,我应该说清楚我正在使用mysql
    【解决方案3】:

    您可以通过使用 ILIKE 的简单查询来实现此目的

    str = ["The","Ruby"].map {|val| "%#{val}%" }
    
    Video.where("category_title ILIKE ANY ( array[?] ) OR title ILIKE ANY (array[?] ) OR description ILIKE ANY (array[?] ) OR tag_list ILIKE ANY (array[?] )", str, str, str, str)
    

    它对我有用。

    干杯!

    【讨论】:

    • Error ActiveRecord::StatementInvalid: Mysql2::Error: You have an error in your SQL syntax;检查与您的 MySQL 服务器版本相对应的手册,以了解在 'ILIKE ANY (array['%The%','%Ruby%']) 或标题 ILIKE ANY (array['%The%',' %Ruby%'' 在第 1 行:SELECT videos.* FROM videos WHERE (category_title ILIKE ANY (array['%The%','%Ruby%']) OR title ILIKE ANY (array['%The %','%Ruby%'] ) OR description ILIKE ANY (array['%The%','%Ruby%'] ) OR tag_list ILIKE ANY (array['%The%','%Ruby%'] ) ) 限制 11
    猜你喜欢
    • 1970-01-01
    • 2013-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-20
    • 2021-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多