匹配字符串中的任意字母
Match any letter in a string
Table flights
:
ID
Path
1
NZ:EU
2
JP:CA
SELECT
path
FROM
flights
WHERE
path ILIKE '%' || 'jpca' || '%'
以上查询无效,需要 return 第二行。但是如果我提供例如:
- 日本
- 约
- p
- 日本:加拿大
- 加拿大
它也适用于:
- 日本警察协会
- pj
- cp
- a:p
也接受正则表达式答案。
如果在匹配前处理 path
列会容易得多
匹配单个字符
(更新问题。)
假设:
- 所有字符都有意义,包括标点符号。
- 如果在
path
中找到每个字符,则模式匹配。
- 匹配case-insensitive.
Lower-case 两个操作数并将它们视为 数组.
如果可以有重复的字母,为了效率,去掉它们。
SELECT path
FROM flights
WHERE string_to_array(lower(path), null)
@> string_to_array(lower('JPCA'), null);
或:
...
WHERE string_to_array(lower(path), null) @> '{j,p,c,a}';
Returns 路径包含搜索模式中每个字符的所有行。
@>
is the array "contains" operator.
如果 table 很大,在表达式上用 GIN 索引 支持它以使其更快(这是这条路线的重点):
CREATE INDEX flights_path_array_lower_gin_idx ON flights
USING gin (string_to_array(lower(path), null));
相关,包含指向更多内容的链接:
如果你不需要索引支持,简单的检查就可以了:
...
WHERE path ~* ALL (string_to_array('JPCA', null))
~*
是 case-insensitive 正则表达式匹配运算符。
相关:
- Difference between LIKE and ~ in Postgres
- Check if value exists in Postgres array
- Pattern matching with LIKE, SIMILAR TO or regular expressions in PostgreSQL
- Escape function for regular expression or LIKE patterns
子串匹配
(原题。)
假设:
- 必须匹配搜索词中的字符序列。
- 只有 ASCII 字母才有意义
- 重复字符很重要
SELECT path
FROM flights
WHERE lower(regexp_replace(path, '[^a-zA-Z]', '', 'g')) ~ lower('JPCA');
这将删除除 A-Z 和 a-z 之外的所有字符,并在尝试正则表达式匹配之前将结果转换为小写。相关:
- LOWER LIKE vs iLIKE
如果你的 table 很大并且你需要它很快,创建一个三元组 expression index:
CREATE INDEX flights_path_expr_idx ON flights
USING gin (lower(regexp_replace(path, '[^a-zA-Z]', '', 'g') gin_trgm_ops);
需要安装附加模块 pg_trgm
。参见:
- PostgreSQL LIKE query performance variations
或 添加一个“生成的列”到您的 table 和一个普通的 B-tree 索引:
ALTER TABLE flights
ADD COLUMN path_ascii text GENERATED ALWAYS AS (lower(regexp_replace(path, '[^a-zA-Z]', '', 'g'))) STORED;
CREATE INDEX flights_path_ascii_trgm_idx ON flights USING gin (path_ascii gin_trgm_ops);
然后:
SELECT path FROM flights WHERE path_ascii ~ 'jpca';
参见:
- Computed / calculated / virtual / derived columns in PostgreSQL
如果您不希望您的字词中的字符完全按照该顺序出现,而只想在某处指定与这些字符中的每一个匹配的搜索,则可以使用 ALL
keyword 来匹配一次有多个 ILIKE
个模式:
SELECT path
FROM flights
WHERE path ILIKE ALL( ARRAY['%j%', '%p%', '%c%', '%a%'] );
现在要从单个字符串生成该数组,您可以使用
SELECT *
FROM flights
WHERE path ILIKE ALL (SELECT '%' || regexp_split_to_table('jpca', '') || '%');
Table flights
:
ID | Path |
---|---|
1 | NZ:EU |
2 | JP:CA |
SELECT
path
FROM
flights
WHERE
path ILIKE '%' || 'jpca' || '%'
以上查询无效,需要 return 第二行。但是如果我提供例如:
- 日本
- 约
- p
- 日本:加拿大
- 加拿大
它也适用于:
- 日本警察协会
- pj
- cp
- a:p
也接受正则表达式答案。
如果在匹配前处理 path
列会容易得多
匹配单个字符
(更新问题。)
假设:
- 所有字符都有意义,包括标点符号。
- 如果在
path
中找到每个字符,则模式匹配。 - 匹配case-insensitive.
Lower-case 两个操作数并将它们视为 数组.
如果可以有重复的字母,为了效率,去掉它们。
SELECT path
FROM flights
WHERE string_to_array(lower(path), null)
@> string_to_array(lower('JPCA'), null);
或:
...
WHERE string_to_array(lower(path), null) @> '{j,p,c,a}';
Returns 路径包含搜索模式中每个字符的所有行。
@>
is the array "contains" operator.
如果 table 很大,在表达式上用 GIN 索引 支持它以使其更快(这是这条路线的重点):
CREATE INDEX flights_path_array_lower_gin_idx ON flights
USING gin (string_to_array(lower(path), null));
相关,包含指向更多内容的链接:
如果你不需要索引支持,简单的检查就可以了:
...
WHERE path ~* ALL (string_to_array('JPCA', null))
~*
是 case-insensitive 正则表达式匹配运算符。
相关:
- Difference between LIKE and ~ in Postgres
- Check if value exists in Postgres array
- Pattern matching with LIKE, SIMILAR TO or regular expressions in PostgreSQL
- Escape function for regular expression or LIKE patterns
子串匹配
(原题。)
假设:
- 必须匹配搜索词中的字符序列。
- 只有 ASCII 字母才有意义
- 重复字符很重要
SELECT path
FROM flights
WHERE lower(regexp_replace(path, '[^a-zA-Z]', '', 'g')) ~ lower('JPCA');
这将删除除 A-Z 和 a-z 之外的所有字符,并在尝试正则表达式匹配之前将结果转换为小写。相关:
- LOWER LIKE vs iLIKE
如果你的 table 很大并且你需要它很快,创建一个三元组 expression index:
CREATE INDEX flights_path_expr_idx ON flights
USING gin (lower(regexp_replace(path, '[^a-zA-Z]', '', 'g') gin_trgm_ops);
需要安装附加模块 pg_trgm
。参见:
- PostgreSQL LIKE query performance variations
或 添加一个“生成的列”到您的 table 和一个普通的 B-tree 索引:
ALTER TABLE flights
ADD COLUMN path_ascii text GENERATED ALWAYS AS (lower(regexp_replace(path, '[^a-zA-Z]', '', 'g'))) STORED;
CREATE INDEX flights_path_ascii_trgm_idx ON flights USING gin (path_ascii gin_trgm_ops);
然后:
SELECT path FROM flights WHERE path_ascii ~ 'jpca';
参见:
- Computed / calculated / virtual / derived columns in PostgreSQL
如果您不希望您的字词中的字符完全按照该顺序出现,而只想在某处指定与这些字符中的每一个匹配的搜索,则可以使用 ALL
keyword 来匹配一次有多个 ILIKE
个模式:
SELECT path
FROM flights
WHERE path ILIKE ALL( ARRAY['%j%', '%p%', '%c%', '%a%'] );
现在要从单个字符串生成该数组,您可以使用
SELECT *
FROM flights
WHERE path ILIKE ALL (SELECT '%' || regexp_split_to_table('jpca', '') || '%');