我正在使用PostgreSQL 9.4和一个包含名为teams
的{{1}}列的表jsonb
。我正在寻找一个查询,我可以让所有在其玩家阵列中拥有玩家json
,3
和4
的球队。
该表包含两行,其中包含以下7
数据:
第一行:
json
第二行:
{
"id": 1,
"name": "foobar",
"members": {
"coach": {
"id": 1,
"name": "A dude"
},
"players": [
{
"id": 2,
"name": "B dude"
},
{
"id": 3,
"name": "C dude"
},
{
"id": 4,
"name": "D dude"
},
{
"id": 6,
"name": "F dude"
},
{
"id": 7,
"name": "G dude"
}
]
}
}
查询如何获得所需的团队列表?我已经尝试了一个查询,我会从成员玩家{
"id": 2,
"name": "bazbar",
"members": {
"coach": {
"id": 11,
"name": "A dude"
},
"players": [
{
"id": 3,
"name": "C dude"
},
{
"id": 5,
"name": "E dude"
},
{
"id": 6,
"name": "F dude"
},
{
"id": 7,
"name": "G dude"
},
{
"id": 8,
"name": "H dude"
}
]
}
}
创建一个数组并进行比较,但我能够完成的任务都是团队中可用的任何比较玩家ID的结果,而不是所有这些。
答案 0 :(得分:13)
你一次面临两个非平凡的任务。我很感兴趣。
jsonb
。首先,为jsonb_populate_recordset()
注册一个行类型。您可以使用CREATE TYPE
永久创建类型,也可以创建临时表以供临时使用(在会话结束时自动删除):
CREATE TEMP TABLE foo(id int); -- just "id", we don't need "name"
我们只需要id
,因此请不要包含name
。 Per documentation:
输出
中将省略未出现在目标行类型中的JSON字段
SELECT t.json->>'id' AS team_id, p.players
FROM teams t
, LATERAL (SELECT ARRAY (
SELECT * FROM jsonb_populate_recordset(null::foo, t.json#>'{members,players}')
)
) AS p(players)
WHERE p.players @> '{3,4,7}';
Postgres 9.3中json
的SQL Fiddle(第9.4页尚未提供)。
使用玩家记录提取JSON数组:
t.json#>'{members,players}'
从这些开始,我只删除id
的行:
jsonb_populate_recordset(null::foo, t.json#>'{members,players}')
...并立即将它们聚合成Postgres数组,因此我们在基表中每行保留一行:
SELECT ARRAY ( ... )
所有这些都发生在横向连接中:
, LATERAL (SELECT ... ) AS p(players)
立即过滤生成的数组,只保留我们要查找的数组 - 使用"contains" array operator @>
:
WHERE p.players @> '{3,4,7}'
VOILÀ。
如果你在一个大桌面上经常运行这个查询,你可以创建一个虚假的IMMUTABLE
函数来提取上面的数组,并根据这个函数创建功能性 GIN索引这超级快
“假”因为函数取决于基础行类型,即在目录查找上,并且如果更改则会更改。 (所以要确保它不会改变。)与此类似:
除了:
不要使用json
之类的类型名作为列名(即使允许这样做),这会引发棘手的语法错误并使错误消息混淆。
答案 1 :(得分:1)
我想和上面一样。只有其他条件是我必须进行子串匹配而不是完全匹配。
这就是我最终做的事情(当然是从上面的答案中获得启发)
SELECT t.json->>'name' AS feature_name, f.features::text
FROM teams t
, LATERAL (
SELECT * FROM json_populate_recordset(null::foo, t.json#>'{members,features}')
) AS f(features)
WHERE f.features LIKE '%dud%';
如果有任何帮助,请在此处发布。