SQLite3"LIKE"或PostgreSQL"ILIKE"的通用Ruby解决方案?

gab*_*lal 17 sqlite postgresql search ruby-on-rails pattern-matching

我使用SQLite3进行开发,使用PostgreSQL进行部署.但是,我面临以下问题:

我的简单搜索使用SQLite3:

def self.search(search)
    if search
      find(:all, :conditions => ["style LIKE ? OR construction LIKE ?", "%#{search}%", "%#{search}%"])
    else
      find(:all)
    end
end
Run Code Online (Sandbox Code Playgroud)

但是,它不起作用PostgreSQL,我需要替换LIKEfor ILIKE来解决问题:

def self.search(search)
    if search
      find(:all, :conditions => ["style ILIKE ? OR construction ILIKE ?", "%#{search}%", "%#{search}%"])
    else
      find(:all)
    end
end
Run Code Online (Sandbox Code Playgroud)

是否有"Ruby方式"在任何数据库中进行这些搜索?

编辑 - 基于您的答案我不相信我会找到一个通用的Ruby解决方案.

我也跟着Ruby on Rails的教程:学习的榜样导轨-由迈克尔·哈特尔,在最终的Gemfile显示这两个数据库...嗯,令人失望...

Erw*_*ter 46

问题根源在于:

我使用SQLite3进行开发,使用PostgreSQL进行部署.

这是一个坏主意™.你将继续遇到不兼容问题 - 或者更糟糕的是:在完成损害之前没有意识到这一点.
使用相同的RDBMS(PostgreSQL)进行开发和生产,为您节省无意义的麻烦.


当你遇到不幸的设置时,有一个简单的解决方法:

lower(style) LIKE lower(?)
Run Code Online (Sandbox Code Playgroud)

适用于两个平台.

  • lower()如果您提供小写搜索模式,则可以放弃右手.

  • 在标准SQLite中,lower(X)只折叠ASCII字母.有关更多信息,请引用SQLite手册中的核心函数一章:

    lower(X)函数返回字符串X的副本,所有ASCII字符都转换为小写.默认的内置lower()函数仅适用于ASCII字符.要对非ASCII字符进行大小写转换,请加载ICU扩展名.

    强调我的.

  • PostgreSQLlower(X)开箱即用UTF-8.


作为一个受欢迎的副作用,您可以使用表达式上的索引加速 PostgreSQL中的查询,这将比使用和基本索引更快. lower(style)ILIKEstyle

此外,由于PostgreSQL 9.1你可以使用带pg_trgm扩展名的GIN或GIST索引来加速任何 LIKEILIKE查询 - 三元组不区分大小写.此相关答案中的详细说明和链接:


Joh*_*ohn 9

我认为Arel是解决这个问题的最佳方法.它被Rails用于活动记录并且与数据库无关.您的代码在sqlite3或postgres中的工作方式相同,这似乎适合您的情况.使用匹配方法将自动切换到postgres环境中的ilike.例:

users=User.arel_table
User.where(users[:style].matches("%#{search}%").or(users[:construction].matches("%#{search}%")))
Run Code Online (Sandbox Code Playgroud)

您可以从github获取更多信息:https://github.com/rails/arel/


Mic*_*ick 5

不,搜索数据库没有"ruby方式" - Ruby on Rails(特别是ActiveRecord)包含帮助方法,用于在ActiveRecord支持的RDB上执行CRUD操作,但是没有更好的方法可以使用LIKE进行搜索然后示例你提供.

与此讨论相关的Rails文档部分将是ActiveRecord :: FinderMethods.

作为旁注,而不是做find(:all)你可以做所有.

Rails文档使用与用于执行LIKE语句相同的语法,即:

Person.exists?(['name LIKE ?', "%#{query}%"])
Run Code Online (Sandbox Code Playgroud)

使用上述方法是非常安全的.

下面这样的语句不安全的原因是因为where字符串直接传递到您的数据库查询而没有任何清理,这使您的数据库开放利用(即一个简单的撇号params[:first_name]可能会弄乱您的整个查询并使您的数据库易受攻击 - - 特别是SQL注入).在上面的示例中,ActiveRecord可以清理您传递给查询的参数.

Client.where("first_name LIKE '%#{params[:first_name]}%'")
Run Code Online (Sandbox Code Playgroud)