mba*_*jur 3 arrays postgresql pattern-matching jsonb postgresql-9.6
我有一个posts
带有类型列的Postgres 表jsonb
基本上是一个扁平的标签数组。
我需要做的是以某种方式运行一个 LIKE 查询 tags
列元素以便我可以找到具有以部分字符串开头的标签的帖子。
这样的事情在 Postgres 中可能吗?我一直在寻找超级复杂的例子,但没有人描述过这种基本和简单的场景。
我当前的代码可以很好地检查是否有具有特定标签的帖子:
select * from posts where tags @> '"TAG"'
Run Code Online (Sandbox Code Playgroud)
我正在寻找一种在以下方面运行某些东西的方法
select * from posts where tags @> '"%TAG%"'
Run Code Online (Sandbox Code Playgroud)
SELECT *
FROM posts p
WHERE EXISTS (
SELECT FROM jsonb_array_elements_text(p.tags) tag
WHERE tag LIKE '%TAG%'
);
Run Code Online (Sandbox Code Playgroud)
相关,有解释:
或者更简单的@?
操作符,因为 Postgres 12 实现了 SQL/JSON:
SELECT *
-- optional to show the matching item:
-- , jsonb_path_query_first(tags, '$[*] ? (@ like_regex "^ tag" flag "i")')
FROM posts
WHERE tags @? '$[*] ? (@ like_regex "TAG")';
Run Code Online (Sandbox Code Playgroud)
运算符@?
只是函数jsonb_path_exists()
的包装器。所以这是等价的:
...
WHERE jsonb_path_exists(tags, '$[*] ? (@ like_regex "TAG")');
Run Code Online (Sandbox Code Playgroud)
两者都没有索引支持。(@?
稍后可能会为操作员添加,但在第 13 页中尚未添加)。所以这些查询对于大表来说很慢。像 Laurenz 已经建议的标准化设计会更好 - 具有三元组索引:
对于仅前缀匹配(LIKE 'TAG%'
,没有前导通配符),您可以使其与全文索引一起使用:
CREATE INDEX posts_tags_fts_gin_idx ON posts USING GIN (to_tsvector('simple', tags));
Run Code Online (Sandbox Code Playgroud)
和一个匹配的查询:
SELECT *
FROM posts p
WHERE to_tsvector('simple', tags) @@ 'TAG:*'::tsquery
Run Code Online (Sandbox Code Playgroud)
或者english
,simple
如果您想要词干自然英语,请使用字典而不是(或任何适合您的情况)。
to_tsvector(json(b))
需要Postgres 10或更高版本。
有关的: