snippetsqlMinor
Create smaller row from alias and preserve column names
Viewed 0 times
createcolumnpreservenamessmallerandfromrowalias
Problem
Using Postgres:
currently produces
however I would like not to have the "id" field in the JSON output.
changing the sites selection to
causes the fields to lose their names
and attempting (what would be a horrible) sub selection
understandably throws an
ERROR: relation "sites" does not exist
And removing the id with a select in the from clause prevents joining the tables.
I'm looking to preserve the column information as well as I can, not just for conversion to JSON but for inclusion in much larger and complex queries, so performing the array selection without using JSON is preferred.
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
;currently produces
"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"}]"
however I would like not to have the "id" field in the JSON output.
changing the sites selection to
array_to_json(array_agg(row(sites."name", sites.created))) as sitescauses the fields to lose their names
"[{"f1":"Village","f2":"2015-08-10T15:22:36.622298"},
{"f1":"Manor","f2":"2015-08-10T15:22:43.614551"}]"
and attempting (what would be a horrible) sub selection
, array_to_json(array_agg((SELECT "name", created FROM sites))) as sitesunderstandably throws an
ERROR: relation "sites" does not exist
And removing the id with a select in the from clause prevents joining the tables.
I'm looking to preserve the column information as well as I can, not just for conversion to JSON but for inclusion in much larger and complex queries, so performing the array selection without using JSON is preferred.
Solution
Unfortunately, a
And
The question has been answered before - with detailed explanation and links:
To preserve column names in a plain array (not JSON or hstore), you need to use a registered row type for the row, else column names are lost in any case.
Either you already have a matching row type, or you register one (temporarily):
Then:
Details in the linked answer.
ROW() expression does not preserve column names. Use a subselect instead.And
json_agg() is simpler and faster for the task: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 PKThe question has been answered before - with detailed explanation and links:
- Select columns inside json_agg
To preserve column names in a plain array (not JSON or hstore), you need to use a registered row type for the row, else column names are lost in any case.
Either you already have a matching row type, or you register one (temporarily):
CREATE TEMP TABLE tmp_site(name text, created timestamptz) -- use your data types!Then:
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.idDetails in the linked answer.
Code Snippets
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 PKCREATE TEMP TABLE tmp_site(name text, created timestamptz) -- use your data types!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.idContext
StackExchange Database Administrators Q#110613, answer score: 5
Revisions (0)
No revisions yet.