Yan*_*hon 41 postgresql group-by row json
我有一个查询,如:
SELECT a.id, a.name, json_agg(b.*) as "item"
FROM a
JOIN b ON b.item_id = a.id
GROUP BY a.id, a.name;
Run Code Online (Sandbox Code Playgroud)
如何选择在列b,所以我没有b.item_id在JSON对象?
我读过关于ROW,但它返回一个 JSON 对象,如:
{"f1": "Foo", "f2": "Bar"}
Run Code Online (Sandbox Code Playgroud)
一旦获取它以匹配正确的列键,我将需要重新映射 JSON 对象。我想避免这种情况并保留原始列名。
Erw*_*ter 75
不幸的是,SQL 语法中没有规定“除这一列之外的所有列”。您可以通过在行类型表达式中拼出剩余的列列表来实现您的目标:
SELECT a.id, a.name
, json_agg((b.col1, b.col2, b.col3)) AS item
FROM a
JOIN b ON b.item_id = a.id
GROUP BY a.id, a.name;Run Code Online (Sandbox Code Playgroud)
这是更明确形式的缩写:.ROW(b.col1, b.col2, b.col3)
但是,列名称不会保留在行类型表达式中。您可以通过这种方式在 JSON 对象中获得通用键名。我看到 3 个保留原始列名的选项:
转换为众所周知的(注册的)行类型。为每个现有表或视图或使用显式CREATE TYPE语句注册类型。您可以将临时表用于临时解决方案(在会话期间有效):
CREATE TEMP TABLE x (col1 int, col2 text, col3 date); -- use adequate data types!
SELECT a.id, a.name
, json_agg((b.col1, b.col2, b.col3)::x) AS item
FROM a
JOIN b ON b.item_id = a.id
GROUP BY a.id, a.name;Run Code Online (Sandbox Code Playgroud)
使用子选择来构造派生表并作为一个整体引用该表。这也带有列名。它更冗长,但您不需要注册类型:
SELECT a.id, a.name
, json_agg((SELECT x FROM (SELECT b.col1, b.col2, b.col3) AS x)) AS item
FROM a
JOIN b ON b.item_id = a.id
GROUP BY a.id, a.name;Run Code Online (Sandbox Code Playgroud)
json_build_object()在 Postgres 9.4 或更高版本中SELECT a.id, a.name
, json_agg(json_build_object('col1', b.col1, 'col2', b.col2, 'col3', b.col3)) AS item
FROM a
JOIN b ON b.item_id = a.id
GROUP BY a.id, a.name;Run Code Online (Sandbox Code Playgroud)
有关的:
与jsonb各自的功能类似jsonb_agg()和jsonb_build_object()。
对于Postgres 9.5或更高版本,还可以看到a_horse 的答案,其中包含一个新的更短的语法变体:Postgres 添加了减号运算符-,jsonb用于表示“除此一个键之外的所有键”。
由于Postgres 10 “除了几个键”是用相同的运算符实现的,text[]作为第二个操作数 - 如 mlt 评论。
a_h*_*ame 24
从 9.6 开始,您可以简单地使用-从 JSONB 中删除密钥:
SELECT a.id, a.name, jsonb_agg(to_jsonb(b) - 'item_id') as "item"
FROM a
JOIN b ON b.item_id = a.id
GROUP BY a.id, a.name;
Run Code Online (Sandbox Code Playgroud)
to_jsonb(b)将转换整行,- 'item_id'然后将删除带有名称item_id的键,然后聚合结果。
小智 13
您实际上可以在没有 group by 的情况下使用子查询来完成
SELECT
a.id, a.name,
(
SELECT json_agg(item)
FROM (
SELECT b.c1 AS x, b.c2 AS y
FROM b WHERE b.item_id = a.id
) item
) AS items
FROM a;
Run Code Online (Sandbox Code Playgroud)
返回
{
id: 1,
name: "thing one",
items:[
{ x: "child1", y: "child1 col2"},
{ x: "child2", y: "child2 col2"}
]
}
Run Code Online (Sandbox Code Playgroud)
John Atten 的这篇文章真的很有趣,而且有更多细节
小智 5
您可以使用json_build_object这样的
SELECT
a.id,
a.name,
json_agg(json_build_object('col1', b.col1, 'col2', b.col2) AS item
FROM a
JOIN b ON b.item_id = a.id
GROUP BY a.id, a.name;
Run Code Online (Sandbox Code Playgroud)