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吗?