如何过滤json列中嵌套值的行?

Nil*_*lor 5 sql postgresql json nested

这是我的表格(简化的,只有重要的列):

CREATE TABLE things (
  id serial primary key
, name varchar
, blueprint json default '{}'
);
Run Code Online (Sandbox Code Playgroud)

以及一些示例数据:

# 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"}}
Run Code Online (Sandbox Code Playgroud)

我想选择键'Azamund'下任意位置的行name。像这样的东西:

# 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"}}
Run Code Online (Sandbox Code Playgroud)

数据的嵌套与示例中完全一样(只有一层)。
目前我们使用的是 PostgreSQL 9.3.5。

在 PostgreSQL 9.3 中可能吗?也许9.4?

Erw*_*ter 5

您的查询已接近。json_each()是关键功能。或者jsonb_each()对于jsonb. 一些改进:

SELECT *
FROM   things t
WHERE  EXISTS (
   SELECT FROM json_each(t.blueprint) b
   WHERE  b.value->>'name' ILIKE 'azamund'
   );
Run Code Online (Sandbox Code Playgroud)

db<>在这里
摆弄旧的sqlfiddle

json_each()已经返回json值。不需要额外的演员。

更好的是,LATERAL使用EXISTS. 这比使用列表中的集合返回函数取消嵌套要干净得多SELECT。看:

用于ILIKE模式匹配。正则表达式匹配 ( ~, ~*) 更通用,但也更昂贵。因此,尽可能使用基本的LIKE/ 。ILKE看:

JSON 数组的替代方案

您已经看到了我对 JSON 数组的相关回答:

虽然嵌套 JSON 对象的查询看起来很简单,但数组有卓越的索引支持:

在 Postgres 12+ 中使用JSON/PATH 表达式

语法虽然复杂,但查询变得更简单、更高效。还可以使用以下形式的索引:

CREATE INDEX things_blueprint_gin_idx ON things USING gin (blueprint);
Run Code Online (Sandbox Code Playgroud)
CREATE INDEX things_blueprint_gin_idx ON things USING gin (blueprint);
Run Code Online (Sandbox Code Playgroud)

不区分大小写:

SELECT *
FROM   things t
WHERE  t.blueprint @? '$.* ? (@.name == "Azamund")';
Run Code Online (Sandbox Code Playgroud)

对于数组变体,我们还可以使用具有更高效的运算符类的索引jsonb_path_ops

CREATE INDEX things_arr_foo_path_ops ON things_arr USING gin (blueprint jsonb_path_ops);
Run Code Online (Sandbox Code Playgroud)
SELECT *
FROM   things t
WHERE  t.blueprint @? '$.* ? (@.name like_regex "^azamund$" flag "i")';
Run Code Online (Sandbox Code Playgroud)

不区分大小写:

CREATE INDEX things_arr_foo_path_ops ON things_arr USING gin (blueprint jsonb_path_ops);
Run Code Online (Sandbox Code Playgroud)

db<>在这里摆弄

有关的:


归档时间:

查看次数:

6356 次

最近记录:

6 年,3 月 前