从别名创建较小的行并保留列名

Gau*_*uss 7 postgresql aggregate row

使用 Postgres:

SELECT users."name" AS "name"
    , array_to_json(array_agg(sites)) as sites
FROM remodel.users AS users
JOIN remodel.user_sites AS user_sites
    ON users.id=user_sites.user
JOIN remodel.sites AS sites
    ON sites.id=user_sites.site
GROUP BY "users".id
;
Run Code Online (Sandbox Code Playgroud)

目前生产

SELECT users."name" AS "name"
    , array_to_json(array_agg(sites)) as sites
FROM remodel.users AS users
JOIN remodel.user_sites AS user_sites
    ON users.id=user_sites.user
JOIN remodel.sites AS sites
    ON sites.id=user_sites.site
GROUP BY "users".id
;
Run Code Online (Sandbox Code Playgroud)

但是我不想在 JSON 输出中有“id”字段。

将站点选择更改为

array_to_json(array_agg(row(sites."name", sites.created))) as sites
Run Code Online (Sandbox Code Playgroud)

导致字段失去名称

"Toby";"[{"id":1,"name":"Village","created":"2015-08-10T15:22:36.622298"},
         {"id":2,"name":"Manor","created":"2015-08-10T15:22:43.614551"}]"
"Amy";"[{"id":3,"name":"Park","created":"2015-08-10T15:22:48.810872"}]"
"Anne";"[{"id":2,"name":"Manor","created":"2015-08-10T15:22:43.614551"},
         {"id":1,"name":"Village","created":"2015-08-10T15:22:36.622298"},
         {"id":3,"name":"Park","created":"2015-08-10T15:22:48.810872"}]"
Run Code Online (Sandbox Code Playgroud)

并尝试(这将是一个可怕的)子选择

, array_to_json(array_agg((SELECT "name", created FROM sites))) as sites
Run Code Online (Sandbox Code Playgroud)

可以理解地抛出一个

错误:关系“站点”不存在

并且在 from 子句中使用 select 删除 id 会阻止加入表。

我希望尽可能地保留列信息,不仅用于转换为 JSON,还用于包含在更大和更复杂的查询中,因此首选不使用 JSON 执行数组选择。

Erw*_*ter 5

不幸的是,ROW()表达式不保留列名。改用子选择
并且json_agg()对于任务来说更简单、更快:

SELECT u.id, u.name
     , json_agg((SELECT x FROM (SELECT s.name, s.created) x)) AS sites
FROM   remodel.users      u
JOIN   remodel.user_sites us ON us.user = u.id
JOIN   remodel.sites      s  ON s.site = us.id
GROUP  BY u.id;  -- id must be the PK
Run Code Online (Sandbox Code Playgroud)

这个问题之前已经回答过 - 有详细的解释和链接:


要在普通数组(不是 JSON 或 hstore)中保留列名,您需要为使用注册的行类型,否则列名在任何情况下都会丢失。
您已经有一个匹配的行类型,或者您注册了一个(临时):

CREATE TEMP TABLE tmp_site(name text, created timestamptz)  -- use your data types!
Run Code Online (Sandbox Code Playgroud)

然后:

SELECT u.id, u.name
     , array_agg((s.name, s.created)::tmp_site) AS sites  -- or whatever you do with s
FROM   remodel.users      u
JOIN   remodel.user_sites us ON us.user = u.id
JOIN   remodel.sites      s  ON us.site = s.id
GROUP  BY u.id
Run Code Online (Sandbox Code Playgroud)

链接答案中的详细信息。


Len*_*art 4

一种想法是创建一个包含您感兴趣的列的内联视图:

SELECT users."name" AS "name"
     , array_to_json(array_agg(sites)) as sites
FROM remodel.users AS users
JOIN remodel.user_sites AS user_sites
    ON users.id=user_sites.user
CROSS JOIN LATERAL (
    SELECT name, created 
    FROM remodel.sites AS s
    WHERE s.id=user_sites.site
) AS sites
GROUP BY "users".id
Run Code Online (Sandbox Code Playgroud)

通过使用,LATERAL您可以在内联视图中引用“同级”。由于JOIN条件是视图的一部分,因此CROSS JOIN可以使用 a。