Skip to Main Content
  • Questions
  • Group By, Group By Rollup, and Grouping Sets

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Brian.

Asked: February 17, 2009 - 11:26 am UTC

Last updated: February 17, 2009 - 11:35 am UTC

Version: 10.2.0

Viewed 1000+ times

You Asked

It always bothers me when I have to kluge a query to get it to work.

I have a table of questionnaires and the person who completed each one.
create table ques_set (ques_set_id int, pers_id int);

insert into ques_set values (1,48);
insert into ques_set values (2,93);
insert into ques_set values (3,64);
insert into ques_set values (4,72);
insert into ques_set values (5,48);
insert into ques_set values (6,72);
insert into ques_set values (7,56);
insert into ques_set values (8,64);
insert into ques_set values (9,81);
insert into ques_set values (10,72);
commit;

From this, I would like to know: how many people created questionnaires; how many people created 1 questionnaire, 2 questionnaires, etc.; how many total questionnaire uses that translates to; and grand totals for people and uses.

Like so:
USE_PER_PERS   PERS   USE
           1      3     3   -- 3 people have created 1 questionnaire for a
                            --    total of 3 questionnaires
           2      2     4   -- 2 people have created 2 questionnaires for a
                            --    total of 4 questionnaires
           3      1     3   -- 1 person has created 3 questionnaires for a
                            --    total of 3 questionnaires
       Total      6    10   -- 6 people have created a total of 10
                            --    questionnaires

A couple of your postings really helped me formulate this query and it works. However, when I get to that last step (working from the innermost sub-query out - step(5) in my comments), I have to place a bogus aggregate function on the 'pers' and 'use' columns in order to do the final 'group by'. I used 'sum' but 'min', 'max', 'avg', etc. would also work.
-- (5) group the aggregates to get 'Total' into one rec instead of two
select
   use_per_pers,
   sum(pers) as pers,
   sum(use) as use
from
   (
   -- (4) identify the sums for num of persons and num of uses
   select
      nvl2(use_per_pers,to_char(lpad(use_per_pers,12)),lpad('Total',12))
         as use_per_pers,
      pers,
      use
   from
      (
      -- (3) calc the total number of uses
      select
         use_per_pers,
         pers,
         sum(use_per_pers*pers) as use
      from
         (
         -- (2) the number of people who have 1, 2, 3, etc. ques sets
         select
            use_per_pers,
            count(pers_id) pers
         from
            (
            -- (1) the number of ques sets for each pers
            select
               pers_id,
               count(*) use_per_pers
            from ques_set
            group by pers_id
            )
         group by rollup(use_per_pers)
         )
      group by grouping sets ((),(use_per_pers,pers))
      )
   )
group by use_per_pers
order by use_per_pers
/

Am I being too anal or is there a better way?

Thanks.

Brian

and Tom said...

... It always bothers me when I have to kluge a query to get it to work. ...

Yes, me too - it almost always means the underlying structures were not thought out.

but in this case - it looks OK, we can do this simply:

ops$tkyte%ORA10GR2> select decode( grouping(cnt), 0, to_char(cnt,'999,999'), 'Total:' ) use_per_pers,
  2         count(*) pers,
  3             decode( grouping(cnt), 0, count(*)*cnt, sum(cnt) ) use
  4    from (
  5  select pers_id, count(*) cnt
  6    from ques_set
  7   group by pers_id
  8         )
  9   group by rollup( cnt )
 10   order by cnt
 11  /

USE_PER_       PERS        USE
-------- ---------- ----------
       1          3          3
       2          2          4
       3          1          3
Total:            6         10



get the counts by pers_id (lines 5-7)

and then just aggregate that up - with a rollup to get the extra total line.

Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

I Like 'Simple'

Brian, February 17, 2009 - 2:37 pm UTC

Very instructional, Tom. It did seem like I was having to work very hard to get the result. You simplified it quite nicely.

Thanks.