我有一张表,其中有城市作为 jsonb 列,其中有 json 数组,如下所示
[{"name":"manchester",..},{"name":"liverpool",....}]
现在我想用 ILIKE 查询查询“name”列上的表。
我已经尝试过以下但对我不起作用
select * from data where city->>'name' ILIKE '%man%'
虽然我知道,我可以通过以下查询进行完全匹配的搜索
select * from data where city->>'name' @> 'manchester'
我也知道我们可以使用 jsonb 函数来制作平面数据和搜索,但它不会使用索引。
无论如何都可以用 ilike 搜索数据,它也使用索引吗?
答案 0 :(得分:0)
索引支持会很困难;为此,遵循第一范式的模式将是有益的。
除此之外,您可以从 v12 开始使用 JSONPATH 语言:
WITH t(c) AS (
SELECT '[{"name":"manchester"},{"name":"liverpool"}]'::jsonb
)
SELECT jsonb_path_exists(
c,
'$.**.name ? (@ like_regex "man" flag "i")'::jsonpath
)
FROM t;
jsonb_path_exists
═══════════════════
t
(1 row)
答案 1 :(得分:0)
您确实应该以不同的方式存储数据。
您可以“自然地”执行 ilike 查询,但无需索引支持,如下所示:
select * from data where exists (select 1 from jsonb_array_elements(city) f(x) where x->>'name' ILIKE '%man%');
您可以像这样获得索引支持:
create index on data using gin ((city::text) gin_trgm_ops);
select * from data where city::text ilike '%man%';
但它会在键的文本中找到匹配,以及值,并且使用任何存在的不相关键/值。您可以通过创建一个只返回值的函数来解决这个问题,所有值都组合成一个字符串,然后使用函数索引。但是,随着字符串长度变长,索引的效果会越来越差,因为会有更多的误报需要追踪和剔除。
create or replace function concat_val(jsonb, text) returns text immutable language sql as $$
select string_agg(x->>$2,' ') from jsonb_array_elements($1) f(x)
$$ parallel safe;
create index on data using gin (concat_val(city,'name') gin_trgm_ops);
select * from data where concat_val(city,'name') ilike '%man%';
您确实应该以不同的方式存储数据。