Sql 在RubyonRails3中组合名字和姓氏列的最佳方法?

Sql 在RubyonRails3中组合名字和姓氏列的最佳方法?,sql,ruby-on-rails,ruby,Sql,Ruby On Rails,Ruby,我的用户模型中有一个方法: 但是,如果我的用户能够在同一个查询中同时搜索名字和姓氏,那就太好了 我想创建一个虚拟属性,如下所示: def full_name [first_name, last_name].join(' ') end 但这在数据库级别上是有效的。或者有没有更快的方法来检索搜索结果 感谢您的帮助。示例中的虚拟属性只是类方法,不能由类似查找的ActiveRecord方法用于查询数据库 检索搜索结果的最简单方法是修改搜索方法: 在我的示例中,varchar连接语法与您选择的数据库

我的用户模型中有一个方法:

但是,如果我的用户能够在同一个查询中同时搜索名字和姓氏,那就太好了

我想创建一个虚拟属性,如下所示:

def full_name
  [first_name, last_name].join(' ')
end
但这在数据库级别上是有效的。或者有没有更快的方法来检索搜索结果


感谢您的帮助。

示例中的虚拟属性只是类方法,不能由类似查找的ActiveRecord方法用于查询数据库

检索搜索结果的最简单方法是修改搜索方法:


在我的示例中,varchar连接语法与您选择的数据库MS SQL兼容。

在您的示例中,搜索功能仍将在SQL级别运行

因此,按照您的示例,您的搜索代码可能是:

def self.search_full_name(query)
  q = "%#{query}%"
  where('last_name LIKE ? OR first_name LIKE ?', [q, q])
end

注意-这些类型的类似查询,因为它们在前缀处有一个通配符,在大型数据集上会很慢,即使它们被索引。

实现这一点的一种方法是对搜索查询进行标记化拆分,并为每个标记创建一个where条件:

  def self.search(query)
    conds  = []
    params = {}
    query.split.each_with_index do |token, index|
      conds.push "first_name LIKE :t#{index} OR last_name LIKE :t#{index}"
      params[:"t#{index}"] = "%#{token}%"
    end

    where(conds.join(" OR "), params)
  end
还要确保防止SQL注入攻击

不过,最好使用全文搜索工具,如ElasticSearch及其名为Tire的Ruby gem来处理搜索


编辑:修复了代码。可以创建一个范围来处理复杂模式,下面是我正在处理的一个项目的示例:

   scope :search_by_name, lambda { |q|
      if q
        case q
        when  /^(.+),\s*(.*?)$/
         where(["(last_name LIKE ? or maiden_name LIKE ?) AND (first_name LIKE ? OR common_name LIKE ? OR middle_name LIKE ?)",
           "%#{$1}%","%#{$1}%","%#{$2}%","%#{$2}%","%#{$2}%"
           ])
        when /^(.+)\s+(.*?)$/
          where(["(last_name LIKE ? or maiden_name LIKE ?) AND (first_name LIKE ? OR common_name LIKE ? OR middle_name LIKE ?)",
            "%#{$2}%","%#{$2}%","%#{$1}%","%#{$1}%","%#{$1}%"
            ])
        else
           where(["(last_name LIKE ? or maiden_name LIKE ? OR first_name LIKE ? OR common_name LIKE ? OR middle_name LIKE ?)",
             "%#{q}%","%#{q}%","%#{q}%","%#{q}%","%#{q}%"
             ])
        end
      else
       {}
      end
}
如您所见,我进行正则表达式匹配以检测不同的模式,并根据提供的内容构建不同的搜索。作为额外的奖励,如果没有提供任何内容,它将返回一个空散列,该散列实际上是wheretrue并返回所有结果


正如其他地方提到的,如果在两边都使用通配符(如%foo%),则db无法对列进行索引,因此在非常大的数据集上这可能会变慢。

因为模型已经加载,所以不应该有任何数据库含义……嘿,谢谢,这很有效!但仅当在搜索表单中输入了姓或名时。如果输入例如John Doe,则不会检索John Doe记录。如何解决这个问题?我已将我的提案与ms ati post的解决方案结合起来。现在应该与约翰·多伊和多伊·约翰一起工作。工作同样出色。谢谢但是,在同时搜索first_name和last_name时,没有检索到任何记录。您好,看起来很有希望,但我遇到了一个语法错误,不知道如何修复:SQLite3::SQLException:near%:语法错误:从clients.user_id=1和first_name(如%foo%)或last_name(如%foo%)的客户端选择COUNT*
  def self.search(query)
    conds  = []
    params = {}
    query.split.each_with_index do |token, index|
      conds.push "first_name LIKE :t#{index} OR last_name LIKE :t#{index}"
      params[:"t#{index}"] = "%#{token}%"
    end

    where(conds.join(" OR "), params)
  end
   scope :search_by_name, lambda { |q|
      if q
        case q
        when  /^(.+),\s*(.*?)$/
         where(["(last_name LIKE ? or maiden_name LIKE ?) AND (first_name LIKE ? OR common_name LIKE ? OR middle_name LIKE ?)",
           "%#{$1}%","%#{$1}%","%#{$2}%","%#{$2}%","%#{$2}%"
           ])
        when /^(.+)\s+(.*?)$/
          where(["(last_name LIKE ? or maiden_name LIKE ?) AND (first_name LIKE ? OR common_name LIKE ? OR middle_name LIKE ?)",
            "%#{$2}%","%#{$2}%","%#{$1}%","%#{$1}%","%#{$1}%"
            ])
        else
           where(["(last_name LIKE ? or maiden_name LIKE ? OR first_name LIKE ? OR common_name LIKE ? OR middle_name LIKE ?)",
             "%#{q}%","%#{q}%","%#{q}%","%#{q}%","%#{q}%"
             ])
        end
      else
       {}
      end
}