'How to query 3 tables with one to many relationship along with json aggregation?
I have 3 tables like shown below with some sample data:
countries
| id | name | leader |
|---|---|---|
| 1 | India | Narendra Modi |
| 2 | USA | Joe Biden |
| 3 | Australia | Scott Morrison |
states
| id | name | population | country_id |
|---|---|---|---|
| 1 | California | 39500000 | 2 |
| 2 | Washington | 7610000 | 2 |
| 3 | Florida | 21500000 | 2 |
| 4 | Karnataka | 64100000 | 1 |
| 5 | Rajasthan | 68900000 | 1 |
| 6 | Maharastra | 125700000 | 1 |
cities
| id | name | state_id |
|---|---|---|
| 1 | Mumbai | 6 |
| 2 | Pune | 6 |
| 3 | San Francisco | 1 |
I would like to get all the countries with their states and cities queried by population. The result should look like this:
[
{
"country_name": "USA",
"leader": "Joe Biden",
"states": [
{
"state_name": "California",
"population": 39500000,
"cities": [
{
"city_name": "San Fransico"
}
]
}
]
},
{
"country_name": "India",
"leader": "Narendra Modi",
"states": [
{
"state_name": "Maharastra",
"population": 125700000,
"cities": [
{
"city_name": "Mumbai"
},
{
"city_name": "Pune"
}
]
}
]
}
]
I was able to achieve this somewhat with sub queries like this:
select *,
(
select
array_to_json(array_agg(row_to_json(states.*))) as array_to_json
from (
select states.*, (
select
array_to_json(array_agg(row_to_json(cities.*))) as array_to_json
from(
select cities.* from cities where state_id = states.id
) cities) as cities
from states
where country_id = countries.id and population=125700000 OR population = 39500000
) states ) as states
from countries;
But I'd like to use a neat query where I can achieve this using a single join query with JSON aggregators in Postgresql.
Solution 1:[1]
try this
WITH list AS
(
SELECT s.country_id
, jsonb_build_object( 'state_name', s.name ,
, 'population', s.population
, 'cities', jsonb_agg( jsonb_build_object('city_name', c.name))
) AS state_list
FROM states AS s
INNER JOIN cities AS c
ON c.state_id = s.id
GROUP BY s.country_id, s.name, s.population
)
SELECT jsonb_agg( jsonb_build_object( 'country_name', c.name
, 'leader', c.leader
, 'states', l.state_list
)
)
FROM list AS l
INNER JOIN countries AS c
ON c.id = l.country_id
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Edouard |
