1

So I want to aggregate groups of points that share the same location and then count the number of each class that belongs to the point.

My aggregation query is as follows:

create table mytable2 as
select count(*) as rows, location, string_agg(distinct class, ', ' order by class)
from mytable
group by location

The outcome of this gives me a row of for example

 (16, 'Wakanda', 'warrior priest tank')

How do I aggregate it to show instead

(16, 'Wakanda', '10 warrior 5 priest 1 tank')
1
  • 2
    Sample data and desired results as text tables would really help. Where does the 10 come from? Are you talking about multiple rows or multiple columns? Commented Jun 12, 2018 at 11:27

2 Answers 2

1

Example data:

create table mytable(location text, class text);
insert into mytable values
('Wakanda', 'warrior'),
('Wakanda', 'warrior'),
('Wakanda', 'priest'),
('Wakanda', 'tank'),
('Wakanda', 'tank'),
('Wakanda', 'warrior');

Use grouping sets. You can easily get a nice tabular output:

select location, class, count(*)
from mytable
group by grouping sets ((location), (location, class));

 location |  class  | count 
----------+---------+-------
 Wakanda  | priest  |     1
 Wakanda  | tank    |     2
 Wakanda  | warrior |     3
 Wakanda  |         |     6
(4 rows)

or a single row for a location, e.g.:

select
    max(count) as units,
    location, 
    string_agg(class || ': ' || count, ', ') as counts
from (
    select location, class, count(*)
    from mytable
    group by grouping sets ((location), (location, class))
    ) s
group by location;

 units | location |             counts             
-------+----------+--------------------------------
     6 | Wakanda  | priest: 1, tank: 2, warrior: 3
(1 row)
Sign up to request clarification or add additional context in comments.

1 Comment

The format is just what I wanted, however I think your grouping sets is messing with my original count column in my select (I need total count in a separate column). It is showing something like: units 3 | location wakanda | counts tank4 warrior10
1

If I understand correctly, you want two levels of aggregation:

select lc.location,
       string_agg(class || '(' || cnt || ')', ', ' order by cnt desc)
from (select location, class, count(*) as cnt
      from mytable
      group by location, class
     ) lc
group by lc.location;

I put the string in what I consider a more reasonable format. It would look like: 'warrior (10), priest (5), tank (1)'. It is ordered by the frequency. You can (of course) adjust the syntax to get some other format if you like.

1 Comment

Again format is just right but the count is not matching up with my first select (for example, it's counting more warriors than the count(*) in the select)

Your Answer

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.