postgresql 匹配字符串中的任意字母

vjrehmav  于 2023-08-04  发布在  PostgreSQL
关注(0)|答案(2)|浏览(191)

flights
| 路径| Path |
| --| ------------ |
| 新西兰:欧盟| NZ:EU |
| JP:CA| JP:CA |

SELECT
    path
FROM
    flights
WHERE
    path ILIKE '%' || 'jpca' || '%'

字符串
上面的查询不起作用,它需要返回第二行。但它的工作,如果我提供例如:

  • JP
  • CA
  • p
  • jp:ca
  • 计算机辅助设计

它还应有助于:

  • 日本和平协会
  • PJ
  • CP
  • a:p

正则表达式的答案也被接受。

nc1teljy

nc1teljy1#

如果在匹配之前处理列path,则会容易得多

匹配单个字符

(更新问题)
假设条件:

  • 所有字符都有效,包括标点符号。
  • 如果每个字符都在path中找到,则模式匹配。
  • 匹配时不区分大小写。

将两个操作数都小写,并将它们视为数组
如果可能有重复的字母,为了提高效率,请删除它们。

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}';


返回path包含搜索模式中每个字符的所有行。

**@>**是数组的“contains”运算符。

如果表很大,在表达式上使用GIN索引来支持它,以使其更快(这是此路由的点):

CREATE INDEX flights_path_array_lower_gin_idx ON flights
USING gin (string_to_array(lower(path), null));


相关,链接到更多:

  • 即使将enable_seqscan设置为off,也未使用数组列上的GIN索引?
    如果不需要索引支持,简单检查即可:
...
WHERE path ~* ALL (string_to_array('JPCA', null))

**~***是不区分大小写的正则表达式匹配运算符。

相关内容:

子串匹配

(原问题。)
假设条件:

  • 搜索词中的字符序列必须匹配。
  • 只有ASCII字母有效
  • 重复的字符很重要
SELECT path
FROM   flights
WHERE  lower(regexp_replace(path, '[^a-zA-Z]', '', 'g')) ~ lower('JPCA');


这将删除除A-Z和a-z以外的所有字符,并在尝试正则表达式匹配之前将结果转换为小写。相关内容:

  • 从PostgreSQL中的字段中提取数字
  • 低LIKE vs iLIKE

如果你的表很大,你需要它更快,创建一个三元组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查询性能变化
    或者在你的表中添加一个“生成列”和一个普通的B树索引:
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';


请参阅:

  • PostgreSQL中的计算/计算/虚拟/派生列
xmjla07d

xmjla07d2#

如果你不希望词条中的字符按这个顺序出现,而只想指定一个搜索来匹配这些字符中的每一个,你可以使用ALL关键字来同时匹配多个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', '') || '%');


online demo

相关问题