Cel*_*tas 56 regex sql postgresql syntax
我被指示"不要打扰LIKE
"并~
改为使用.什么是错的LIKE
又是怎样的~
不同?
~
在这种情况下是否有名称或者人们说"使用代字号运算符"?
ast*_*asr 47
~
是正则表达式运算符,并具有隐含的功能.您可以指定全范围的正则表达式通配符和量词; 有关详细信息,请参阅文档 当然LIKE
,它需要更强大的功能,并且应该在需要功率时使用,但它们可以用于不同的目的.
Cra*_*ger 33
LIKE
和IMO没有任何不妥,没有理由支持~
它.恰恰相反.LIKE
是SQL标准.所以SIMILAR TO
,但它没有得到广泛支持.PostgreSQL ~ operator
(或posix正则表达式匹配运算符)不是SQL标准.
出于这个原因,我更喜欢使用LIKE
足够表达的地方而我只~
在我需要完整正则表达式的力量时使用.如果我需要移植数据库,那么就会受到一点伤害.我已经倾向于使用SIMILAR TO
什么时候LIKE
不够强大,但在Erwin的评论之后,我想我会停止这样做,并~
在LIKE
不做的时候使用.
此外,PostgreSQL的可以使用前缀搜索(例如B-tree索引LIKE 'TEST%'
)用LIKE
或SIMILAR TO
如果数据库是在C
区域或索引有text_pattern_ops
.与我之前写的相反,Pg也可以将这样的索引用于左锚定的posix正则表达式,它只需要一个显式的'^ TEST.*',因此正则表达式只能从头开始匹配.我之前的帖子错误地指出,~
无法使用索引进行前缀搜索.消除了这种差异,这取决于您是否希望在可能与否之前坚持使用标准兼容功能.
看这个演示SQLFiddle ; 注意不同的执行计划.注意之间的差异~ '1234.*'
和~ '^1234.*'
.
给出样本数据:
create table test (
blah text
);
insert into test (blah) select x::text from generate_series(1,10000) x;
create index test_blah_txtpat_idx ON test(blah text_pattern_ops);
Run Code Online (Sandbox Code Playgroud)
请注意,~
使用seqscan即使它实际上更昂贵(人为因此enable_seqscan
),因为它没有其他选择,同时LIKE
使用索引.但是,~
使用左锚点修正也会使用索引:
regress=# SET enable_seqscan = 'f';
SET
regress=# explain select 1 from test where blah ~ '12.*';
QUERY PLAN
---------------------------------------------------------------------------
Seq Scan on test (cost=10000000000.00..10000000118.69 rows=2122 width=0)
Filter: (blah ~ '12.*'::text)
(2 rows)
regress=# explain select 1 from test where blah like '12%';
QUERY PLAN
------------------------------------------------------------------------------------
Bitmap Heap Scan on test (cost=4.55..46.76 rows=29 width=0)
Filter: (blah ~~ '12%'::text)
-> Bitmap Index Scan on test_blah_txtpat_idx (cost=0.00..4.54 rows=29 width=0)
Index Cond: ((blah ~>=~ '12'::text) AND (blah ~<~ '13'::text))
(4 rows)
regress=# explain select 1 from test where blah ~ '^12.*';
QUERY PLAN
-------------------------------------------------------------------------------------
Bitmap Heap Scan on test (cost=5.28..51.53 rows=101 width=0)
Filter: (blah ~ '^12.*'::text)
-> Bitmap Index Scan on test_blah_txtpat_idx (cost=0.00..5.25 rows=100 width=0)
Index Cond: ((blah ~>=~ '12'::text) AND (blah ~<~ '13'::text))
(4 rows)
Run Code Online (Sandbox Code Playgroud)
Erw*_*ter 28
PostgreSQL中有许多模式匹配运算符.LIKE
,SIMILAR TO
并~
在本手册页中介绍.
如果可以的话,使用LIKE
(~~
),它是最快的.
如果你不能,使用正则表达式(~
),它会更强大.
绝不是用户.这完全没有意义.更进一步.SIMILAR TO
安装附加模块pg_trgm也可以使相似性运算符%
可用.
为了使图片完整,还有自己的基础设施进行文本搜索.
每个运营商都可以获得不同程度的索引支持.它经常胜过其他选择的表现.但即使有索引,细节也有很多余地.
没有pg_trgm,左锚定搜索模式有索引支持.如果你的数据库集群与非"C"语言环境中运行,你需要一个指数具有特殊的运算符类,如@@
或text_pattern_ops
.是的,也支持基本的左锚定正则表达式.例:
CREATE TABLE tbl(string text);
INSERT INTO tbl(string)
SELECT x::text FROM generate_series(1, 10000) x;
CREATE INDEX tbl_string_text_pattern_idx ON tbl(string text_pattern_ops);
SELECT * FROM tbl WHERE string ~ '^1234'; -- left anchored pattern
Run Code Online (Sandbox Code Playgroud)
安装了pg_trgm后,您还可以选择将GIN或GiST索引与运算符类varchar_pattern_ops
或使用gist_trgm_ops
.这些索引可以支持任何 gin_trgm_ops
表达式,而不仅仅是左侧锚定.但是,还没有正则表达式的支持(除了基本的左锚定之外).亚历山大·科罗特科夫和其他人正在努力:
更新:在Postgres 9.3中添加了对任意正则表达式匹配的支持,并且自那以后进行了多次改进.
LIKE
是SQL标准的一部分,但它是非常奇怪的语法,并且PostgreSQL支持它的唯一原因是保持标准兼容.在内部,每个SIMILAR TO
表达式都用正则表达式重写.因此,对于任何给定的SIMILAR TO
表达式,至少有一个正则表达式可以更快地完成相同的工作.我从不使用SIMILAR TO
.更多:
小智 7
该~~
操作相当于LIKE
. ~
另一方面,将使用POSIX正则表达式进行匹配.
我只是做了一个快速而简单的基准测试,以便在没有涉及索引时查看两个运算符之间的性能差异:
postgres=# \timing
Timing is on.
postgres=# SELECT count(1) FROM (SELECT val from generate_series(1, 10000000) x(val) WHERE val::text LIKE '%5%') AS x;
count
?????????
5217031
(1 row)
Time: 5631.662 ms
postgres=# SELECT count(1) FROM (SELECT val from generate_series(1, 10000000) x(val) WHERE val::text ~ '5') AS x;
count
?????????
5217031
(1 row)
Time: 10612.406 ms
Run Code Online (Sandbox Code Playgroud)
在这个例子中,LIKE
操作员几乎是操作员的两倍~
.因此,如果速度是我倾向于的本质LIKE
,但要注意不要过早优化.~
为您提供更多灵活性.
对于那些感兴趣的人,EXPLAIN
以下是上述查询的计划:
postgres=# EXPLAIN ANALYZE SELECT count(1) FROM (SELECT val from generate_series(1, 10000000) x(val) WHERE val::text LIKE '%5%') AS x;
QUERY PLAN
??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
Aggregate (cost=20.00..20.01 rows=1 width=0) (actual time=9967.748..9967.749 rows=1 loops=1)
-> Function Scan on generate_series x (cost=0.00..17.50 rows=1000 width=0) (actual time=1732.084..7404.755 rows=5217031 loops=1)
Filter: ((val)::text ~~ '%5%'::text)
Rows Removed by Filter: 4782969
Total runtime: 9997.587 ms
(5 rows)
postgres=# EXPLAIN ANALYZE SELECT count(1) FROM (SELECT val from generate_series(1, 10000000) x(val) WHERE val::text ~ '5') AS x;
QUERY PLAN
???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
Aggregate (cost=20.00..20.01 rows=1 width=0) (actual time=15118.061..15118.061 rows=1 loops=1)
-> Function Scan on generate_series x (cost=0.00..17.50 rows=1000 width=0) (actual time=1724.591..12516.996 rows=5217031 loops=1)
Filter: ((val)::text ~ '5'::text)
Rows Removed by Filter: 4782969
Total runtime: 15147.950 ms
(5 rows)
Run Code Online (Sandbox Code Playgroud)
小智 6
Like 只是在开头或 End 或 Middle 匹配字符串的一部分并且倾斜 (~) 与正则表达式匹配
为了进一步解释这一点,让我们创建一个表并插入一些值
# create table users(id serial primary key, name character varying);
Run Code Online (Sandbox Code Playgroud)
现在让我们在表中插入一些值
# insert into users (name) VALUES ('Alex'), ('Jon Snow'), ('Christopher'), ('Arya'),('Sandip Debnath'), ('Lakshmi'),('alex@gmail.com'),('@sandip5004'), ('lakshmi@gmail.com');
Run Code Online (Sandbox Code Playgroud)
现在你的桌子应该是这样的
id | name
----+-------------------
1 | Alex
2 | Jon Snow
3 | Christopher
4 | Arya
5 | Sandip Debnath
6 | Lakshmi
7 | alex@gmail.com
8 | lakshmi@gmail.com
9 | @sandip5004
Run Code Online (Sandbox Code Playgroud)
# select * from users where name like 'A%';
id | name
----+------
1 | Alex
4 | Arya
(2 rows)
Run Code Online (Sandbox Code Playgroud)
如您所见, 'A%'
我们只会得到名称以大写字母 A 开头的值。
# select * from users where name like '%a%';
id | name
----+-------------------
4 | Arya
5 | Sandip Debnath
6 | Lakshmi
7 | alex@gmail.com
8 | lakshmi@gmail.com
Run Code Online (Sandbox Code Playgroud)
正如您所看到的, '%a%'
只会为我们获取名称a
介于名称之间的值。
# select * from users where name like '%a';
id | name
----+------
4 | Arya
Run Code Online (Sandbox Code Playgroud)
如您所见, '%a'
我们只会获取名称以a
.
# select * from users where name ~* 't';
id | name
----+----------------
3 | Christopher
5 | Sandip Debnath
Run Code Online (Sandbox Code Playgroud)
正如您所看到的, name ~* 't'
只会为我们获取名称为t
.
~
表示区分大小写, ~* 表示不区分大小写,所以
# select * from users where name ~ 'T';
id | name
----+------
(0 rows)
Run Code Online (Sandbox Code Playgroud)
上面的查询给了我们 0 行,因为T
与任何条目都不匹配
现在让我们考虑一种情况,我们只需要获取电子邮件 ID,我们不知道邮件 ID 有什么,但我们知道电子邮件的模式,即会有一些字母或数字或 _ 或 。或 - 然后是@,然后是更多的字母或数字,或 - 然后。然后com
或in
或org
etc
我们可以使用正则表达式创建模式。
现在让我们尝试使用正则表达式获取结果
# select * from users where name ~* '[a-z0-9\.\-\_]+@[a-z0-9\-]+\.[a-z]{2,5}';
id | name
----+-------------------
7 | alex@gmail.com
8 | lakshmi@gmail.com
Run Code Online (Sandbox Code Playgroud)
同样,我们可以获取一些中间有空格的名称
#select * from users where name ~* '[a-z]+\s[a-z]+';
id | name
----+----------------
2 | Jon Snow
5 | Sandip Debnath
Run Code Online (Sandbox Code Playgroud)
[az]+ 表示可以有从 a 到 z 的任何字母,+ 表示它可能出现 1 次或多次,\s 表示之后会有一个空格,然后又是一组可以出现 1 次或多次的字母次。
希望这个详细的分析有帮助。