1

This is hard to explain but I'll do my best. So to make it simple, I have 3 tables with the following format:

Creator table

id | name
 1 | jack
 2 | doge
 3 | cardano

roads

id | creator_id | length
 1 | 1 | 3
 2 | 1 | 2
 3 | 3 | 9
 4 | 1 | 3

Blocks

id | creator_id | length
 1 | 1 | 4
 2 | 1 | 4
 3 | 3 | 5
 4 | 1 | 3

I can't seem to pick out the rows into columns, otherwise I would be posting here but the query I use to bring the data together is:

select name, layer, sum(length)
from ( SELect a.name, 'road routes'::text as layer, length
 from creator a
 LEFT JOIN road_routes b on a.id = b.creator
 where a.id in (73, 35, 33, 31)
 group by a.name, layer, length
 union
 SELECT a.name, 'block routes'::text as layer, length
 from creator a
 LEFT JOIN block_route b on a.id = b.route_creator
 where a.id in (73, 35, 33, 31)
 group by a.name, layer, length) x
group by layer, name

The expected result and what I need is a table with the following output:

type | jack | doge | cardano | total
roads | 8 | 0 | 9 | 17
blocks | 11 | 0 | 5 | 16

How to sort the data like this?

McNets
24k11 gold badges51 silver badges90 bronze badges
asked Jan 29, 2018 at 14:16
2

1 Answer 1

3

I've used this good answer of Erwin Brandstetter

But keep in mind that your solution requires a dynamic query because I'm sure that creator table has different records from these you has posted here.

create table creator (id int primary key, name text);
insert into creator values (1, 'jack'),(2, 'doge'),(3, 'cardano');
create table roads(id int primary key, creator_id int references creator(id), length int);
insert into roads values (1, 1, 3), (2, 1, 2), (3, 3, 9), (4, 1, 3);
create table blocks(id int primary key, creator_id int references creator(id), length int);
insert into blocks values (1, 1, 4), (2, 1, 4), (3, 3, 5), (4, 1, 3);

I've used a view to get results for roads and blocks.

create view my_view 
as
select 'roads' as subject, c.name,
 coalesce((select sum(length) from roads where creator_id = c.id), 0)::int as length
from creator c
union all
select 'blocks' as subject, c.name,
 coalesce((select sum(length) from blocks where creator_id = c.id), 0)::int as length
from creator c;
select * from 
crosstab 
(
 $$select subject, name, length 
 from my_view
 union all
 select subject, 'total'::text as name, coalesce(sum(length),0)::bigint as length
 from my_view
 group by subject
 order by 1,2$$
)
as t ("subject" text, "cardano" bigint, "doge" bigint, "jack" bigint, "total" bigint)
subject | cardano | doge | jack | total
:------ | ------: | ---: | ---: | ----:
blocks | 5 | 0 | 11 | 16
roads | 9 | 0 | 8 | 17

dbfiddle here

answered Jan 29, 2018 at 17:00
2
  • The fiddle is exactly what I need, thanks! You're right, there are a lot more creators but for this task I only need 4 creators listed plus the total sum Commented Jan 30, 2018 at 12:33
  • 1
    I'm glad to be able to help. Commented Jan 30, 2018 at 12:41

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.