Rails SQL 正则表达式

Posted

技术标签:

【中文标题】Rails SQL 正则表达式【英文标题】:Rails SQL regular expression 【发布时间】:2013-11-15 15:53:00 【问题描述】:

我正在尝试搜索 A0001、A0002、A1234、A2351 等系列中的最大数字...问题是我正在搜索的列表中也有字符串,例如 AG108939、E092357、AL399、 22-30597等...

所以基本上,我想要我的数据库中的最高 A#### 值。我正在使用以下查询:

@max_draw = Drawing.where("drawing_number LIKE ?", "A%")

在 AG309 等数字开始出现问题之前,它一直有效,因为它以 A 开头,但格式与我正在寻找的不同。

我假设这对于正则表达式应该非常简单,但我是新手,不知道如何使用正则表达式正确编写此查询。以下是我尝试过的一些只返回 nil 的方法:

 @max_draw = Drawing.where("drawing_number LIKE ?", /A\d+/)
 @max_draw = Drawing.where("drawing_number LIKE ?", "/A\d+/")
 @max_draw = Drawing.where("drawing_number LIKE ?", "A[0-9]%")

【问题讨论】:

【参考方案1】:

在带有 Postgres 数据库的 Rails 4+ 上,RegEx 查询的一般形式是:

Model.where("column ~* ?", 'regex')

至于正则表达式,它可以是一般的'^A\d+$' 或更具体的'^A\d4$' 分解:

^ - string start anchor
A - literal "A"
\d+ - one or more digits (0-9)
\d4 - exactly four digits
$ - string end anchor

基本上,正则表达式读取“字符串应以 A 开头,后跟四位数字,然后字符串应结束”。 最后的查询行是:

@max_draw = Drawing.where("drawing_number ~* ?", '^A\d4$')

在RubyDoc 或更易于访问的Perl variant 上进一步阅读ruby RegEx(由Sublime text 使用)

【讨论】:

为了完整起见(因为我刚刚遇到):使用~* 表示不区分大小写的正则表达式,使用~ 表示区分大小写。对于否定,只需在前面加上一声 !!~!~* 奇怪的是,只有在“正则表达式”而不是“正则表达式”(单引号)时才有效 是的,Ruby 字符串中的正则表达式存在问题,即“\d”的计算结果为“d”。单引号确实看起来更安全,但遗憾的是排除了插值。 @Epigene 似乎是因为双引号会被转义。您可能只使用('\a' + variable.to_s + '\b')to_s 可能很重要,因为它不是插值,如果类型转换问题不够“粘稠”,它可能会出错。 这个问题是用 sqlite 标记的,所以我认为这不是 100% 的最佳答案......但这正是我对 postgres 所需要的,所以感谢您的回答!【参考方案2】:

你做得很好!缺少的是 REGEXP 函数,该函数用于查询中的正则表达式:

所以在你的情况下使用

Drawing.where("drawing_number REGEXP ?", 'A\d4')
# the 4 defines that there have to be exactly 4 numbers, change if you need to

在 SQL 中,您使用 '-colons,这很奇怪,因为您通常以 /-backslashes 开始正则表达式

【讨论】:

我试过这个并且它抛出一个错误:ActiveRecord::StatementInvalid in DrawingsController#new SQLite3::SQLException: near "REGEX": syntax error: SELECT MAX("drawings"."drawing_number") AS max_id FROM "drawings" WHERE (drawing_number REGEX 'A\d4') 我一开始有错别字,忘记了REGEXP的P 如果你的SQLite没有默认安装REGEXP,可能会出现另一个问题。 ***.com/questions/5071601/… 嗯。它仍然抛出一个错误,但这次它说: SQLite3::SQLException: no such function: REGEXP 所以上面的代码可以工作,但是你知道,它开始将 REGEXP 识别为有效,但是在编写一个好的查询时遇到了问题,说 A 处存在语法错误【参考方案3】:

您不能在 SQL 中使用正则表达式,而这正是您想要做的。最好的办法是像原始代码一样只选择以 A 开头的条目,然后跳过开头有多个字母的条目。

items = Drawing.where( [ 'drawing_number LIKE ?' , 'A%' ] )
max_value = 0
items.each do |item|
  next if item.drawing_number =~ /\A[A-Za-z]2,/
  drawing_number = item.drawing_number.gsub(/\AA/, '').to_i
  max_value = drawing_number if drawing_number > max_value
end

我有理由确定它可以缩短,但这应该可以满足您的需要。

(\A 是行锚的开始,适用于包含换行符的字符串)

(2, 匹配两个或多个前面的字符范围)

http://www.rubular.com/ 非常适合测试 ruby​​ 正则表达式。

【讨论】:

谢谢!像魅力一样工作。 @Xathras - “你不能在 SQL 中使用正则表达式”? PostgreSQL 和 mysql 都支持正则表达式 ^^^ 但是使用正则表达式是否有效(比如次线性时间)? @亚林 @Nuclearman 我在 MySQL 中使用了正则表达式搜索,其速度几乎与等式匹配一样快,即使使用大表也是如此。它可能取决于索引。

以上是关于Rails SQL 正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

你能用rails中的正则表达式做一个where find吗?

Ruby on Rails:不使用 find 时如何为 SQL 清理字符串?

正则表达式去除中文sql

sql正则匹配连续增加数字

如何在sql语句中使用正则表达式

sql server中对字段使用正则表达式替换???