【问题标题】:Rails Dynamic 'Where' clauseRails 动态“Where”子句
【发布时间】:2019-09-26 21:03:08
【问题描述】:

我有一个搜索字段,用户可以在其中输入“Param1”并且我的控制器包含:

Model.where('column_name LIKE ?', "%#{search_field}%")

这被转换为:

SELECT ... FROM table WHERE column_name LIKE '%Param1%'

如果用户输入“Param1”,这可以正常工作,但我希望将其设为逗号分隔的搜索字段。

因此,如果用户输入“Param1,param2”或“Param1,Param2,Param3”,WHERE LIKE 子句应该可以工作,我的想法是根据 ',' 拆分字符串,并且完全不知道如何构建这里的 Model.where 子句,因为它可以是 1 个参数,也可以是 4 个。

【问题讨论】:

    标签: sql ruby-on-rails ruby ruby-on-rails-5


    【解决方案1】:

    如果您使用的是 PostgreSQL,则可以使用 ANY 传递参数的映射数组:

    Model.where('name LIKE ANY(array[?])', params.split(',').map { |val| "%#{val}%" })
    # SELECT "models".*
    # FROM "models"
    # WHERE (name LIKE ANY(array['%param1%','%param2%']))
    

    【讨论】:

      【解决方案2】:

      答案使用与answer of arieljuod相同的方法,但使用Arel API而不是使用纯字符串。

      values = search_field.split(',')
      column_name = Model.arel_table[:column_name]
      query = values.map { |value| column_name.matches("%#{value}%") }.reduce(:or)
      Model.where(query)
      

      【讨论】:

        【解决方案3】:

        这是我在一个项目中所做的:

        values = search_field.split(',').map { |x| "%#{x}%" } # split values and add "%...%"
        count = values.count # count them
        
        # create an array of LIKE operators depending on the values counted
        # if count is 2 then it will be an array: ['column_name LIKE ?', 'column_name LIKE ?']
        where_sql_arr = count.times.map{'column_name LIKE ?'} 
        
        # create the sql query joining with " OR "
        # 'column_name LIKE ? OR column_name LIKE ?'
        where_sql = where_sql_arr.join(' OR ') 
        
        Model.where(where_sql, *values) # note the * before "values" to split the array into multiple arguments
        

        【讨论】:

          【解决方案4】:

          拆分参数是个好主意。

          conditions = "Param1,Param2,Param3, Param4".gsub(" ","").split(',')

          如果没有掩码或正则表达式的搜索就足够了,您可以使用IN查询或AR: Model.where(column_name: conditions)

          否则(至少在 postgresql 中)代码会变得稍微复杂一些。

          从输入字符串构造查询字符串:

          conditions = "Param1,Param2,Param3, Param4".gsub(" ","").split(',')

          query = ("column_name ~* ? OR " * conditions.size)[0...-3] # Delete last unterminated " OR"

          最后

          Model.where(query, *conditions) # splat operator (*) converts array into argument list

          应该可以。

          【讨论】:

          • 我相信这只有在我知道用户要输入 3 个参数时才有效,如果他只输入 2 个呢?
          • 这不会执行多个 LIKE 查询,这将执行一个仅比较相等性的“column_name IN (...)”查询。
          • @LutherSmi 参数的数量可以是任意的。这个想法是将它们变成一个数组,由Model.where(column_name: array) 接受并生成column_name IN (...) 查询。正如@arieljuod 所指出的,这样的查询只搜索完全匹配。我添加了替代解决方案(但是,仅在 postgresql 中进行了测试)。希望对你有帮助
          猜你喜欢
          • 1970-01-01
          • 2019-10-12
          • 2016-12-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-10
          • 2010-09-13
          • 2013-12-19
          相关资源
          最近更新 更多