如何过滤 json 列中嵌套值的行?
How to filter rows on nested values in a json column?
这是我的table(经过简化,只有重要的列):
CREATE TABLE things (
id serial primary key
, name varchar
, blueprint json default '{}'
);
和一些示例数据:
# select * from things;
id | name | blueprint
----+---------+-----------------------------------------------------------------------------
1 | Thing 1 | {}
2 | Thing 2 | {"1":{"name":"Iskapola","wight":"2"}}
3 | Thing 3 | {"1":{"name":"Azamund","weight":"3"}, "2":{"name":"Iskapola","weight":"1"}}
4 | Thing 4 | {"1":{"name":"Ulamir","weight":"1"}, "2":{"name":"Azamund","weight":"1"}}
我想要 select 在 name
键下的任意位置有 'Azamund'
的行。
像这样:
# select * from things where * ->> 'name' = 'Azamund';
id | blueprint
----+----------------------------------------------------------------------------
7 | {"1":{"name":"Azamund","weight":"3"}, "2":{"name":"Iskapola","weight":"1"}}
8 | {"1":{"name":"Ulamir","weight":"1"}, "2":{"name":"Azamund","weight":"1"}}
数据的嵌套与示例中的完全相同(只有一层)。
目前我们使用的是 PostgreSQL 9.3.5.
在 PostgreSQL 9.3 中可以吗?也许是 9.4?
我可以执行的最接近的查询(我需要的 returns 数据)是:
select *
from (select id, (json_each(blueprint)).value::json->>'name' as name
from stocks) as t
where t.name ~* 'azamund';
嗯...也许有更好的东西?
您的查询已结束。 json_each()
是关键函数。或者 jsonb_each()
对应 jsonb
。一些改进:
SELECT *
FROM things t
WHERE EXISTS (
SELECT FROM json_each(t.blueprint) b
WHERE b.value->>'name' ILIKE 'azamund'
);
json_each()
已经 returns 值作为 json
数据类型。不需要额外的转换。
更好的是,在 EXISTS
中使用 LATERAL
引用。这比在 SELECT
列表中使用 set-returning 函数取消嵌套要干净得多。相关:
- Call a set-returning function with an array argument multiple times
使用 ILIKE
(~~*
) 进行模式匹配。正则表达式匹配 (~
, ~*
) 更强大,但也更昂贵。所以尽可能使用基本的 LIKE
/ ILKE
。详情:
替代 JSON 数组
你已经看过我对 JSON 数组的相关回答:
- How do I query using fields inside the new PostgreSQL JSON datatype?
虽然嵌套 JSON 对象的查询看起来很简单,但数组有更好的 索引支持 :
- Index for finding an element in a JSON array
在 Postgres 12 中使用 SQL/JSON 可能会变得更简单/更高效 ...
这是我的table(经过简化,只有重要的列):
CREATE TABLE things (
id serial primary key
, name varchar
, blueprint json default '{}'
);
和一些示例数据:
# select * from things;
id | name | blueprint
----+---------+-----------------------------------------------------------------------------
1 | Thing 1 | {}
2 | Thing 2 | {"1":{"name":"Iskapola","wight":"2"}}
3 | Thing 3 | {"1":{"name":"Azamund","weight":"3"}, "2":{"name":"Iskapola","weight":"1"}}
4 | Thing 4 | {"1":{"name":"Ulamir","weight":"1"}, "2":{"name":"Azamund","weight":"1"}}
我想要 select 在 name
键下的任意位置有 'Azamund'
的行。
像这样:
# select * from things where * ->> 'name' = 'Azamund';
id | blueprint
----+----------------------------------------------------------------------------
7 | {"1":{"name":"Azamund","weight":"3"}, "2":{"name":"Iskapola","weight":"1"}}
8 | {"1":{"name":"Ulamir","weight":"1"}, "2":{"name":"Azamund","weight":"1"}}
数据的嵌套与示例中的完全相同(只有一层)。
目前我们使用的是 PostgreSQL 9.3.5.
在 PostgreSQL 9.3 中可以吗?也许是 9.4?
我可以执行的最接近的查询(我需要的 returns 数据)是:
select *
from (select id, (json_each(blueprint)).value::json->>'name' as name
from stocks) as t
where t.name ~* 'azamund';
嗯...也许有更好的东西?
您的查询已结束。 json_each()
是关键函数。或者 jsonb_each()
对应 jsonb
。一些改进:
SELECT *
FROM things t
WHERE EXISTS (
SELECT FROM json_each(t.blueprint) b
WHERE b.value->>'name' ILIKE 'azamund'
);
json_each()
已经 returns 值作为json
数据类型。不需要额外的转换。更好的是,在
EXISTS
中使用LATERAL
引用。这比在SELECT
列表中使用 set-returning 函数取消嵌套要干净得多。相关:- Call a set-returning function with an array argument multiple times
使用
ILIKE
(~~*
) 进行模式匹配。正则表达式匹配 (~
,~*
) 更强大,但也更昂贵。所以尽可能使用基本的LIKE
/ILKE
。详情:
替代 JSON 数组
你已经看过我对 JSON 数组的相关回答:
- How do I query using fields inside the new PostgreSQL JSON datatype?
虽然嵌套 JSON 对象的查询看起来很简单,但数组有更好的 索引支持 :
- Index for finding an element in a JSON array
在 Postgres 12 中使用 SQL/JSON 可能会变得更简单/更高效 ...