質問

I am using a rollup to get some aggregates and display them to the user in tabular form.

However, I'd like to ensure that within my rollup the number of rows that are rolled up is the same i.e. the number of the largest subset.

I think an example makes what I want much clearer, so I setup a simple example in oracle below:

create table test (
    co_name varchar2(100),
    rtype number,
    some_count number
)         ;
insert all
    into test (co_name, rtype, some_count) values ('A', 1, 5)
    into test (co_name, rtype, some_count) values ('A', 2, 6)
    into test (co_name, rtype, some_count) values ('A', 3, 7)
    into test (co_name, rtype, some_count) values ('B', 1, 8)
    into test (co_name, rtype, some_count) values ('B', 2, 9)
SELECT * FROM DUAL
;

select * from test;
SELECT
    co_name,
    rtype,
    count(some_count)
FROM test
GROUP BY ROLLUP(co_name, rtype)

This gives me the following results :

CO_NAME RTYPE   SOME_COUNT
A       1       5
A       2       6
A       3       7
A               18
B       1       8
B       2       9
B               17
B               35

You'll notice of course that B only has two rows for RTYPE - 1 and 2 That is because there are 0 rows where CO_NAME = B AND RTYPE = 3

Is there a way to keep rollup consistent in the number of results it returns? What I'd like is to see the following:

CO_NAME RTYPE   SOME_COUNT
A       1       5
A       2       6
A       3       7
A               18
B       1       8
B       2       9
B       3       0
B               17
                35

Any suggestions here will be very helpful, as I'd like my application to be stupid and just tabulate the results without having to account for missing data. I'd like the query to give me everything I need.

Thanks!

EDIT: I am a dope... In my sample above I wanted to keep things simple but made a mistake. Instead of RTYPES being a set of {1,2,3} possible values, imagine it is a set of {'x','y','z'} possible values... I did mark an answer as the answer because it answered the question I asked, and the fault is on me :(

役に立ちましたか?

解決

rollup clause will not fill in gaps, you have to do it beforehand:

SQL> with rtypes(col) as(
  2    select level
  3      from ( select max(count(co_name)) as mx_num
  4               from test1
  5              group by co_name
  6            ) t
  7    connect by level <= t.mx_num
  8  )
  9  select t.co_name
 10       , r.col                   as rtype
 11       , sum(nvl(some_count, 0)) as some_count
 12    from test1 t
 13    partition by (t.co_name)
 14    right join rtypes r
 15       on (r.col = t.rtype)
 16  group by rollup(t.co_name, r.col)
 17  ;

Result:

Co_Name rtype   Some_Count
-------------------------------------- 
A       1       5 
A       2       6 
A       3       7 
A               18 
B       1       8 
B       2       9 
B       3       0 
B               17 
                35 

The query in the WITH clause is used to generate RTYPES from 1 to 3 (as it happens 3

is the maximum number for rtype in this case). In the main query we right outer join our

TEST1 table with actual data with RTYPES CTE using partition by() clause.

Find out more about partition join.


Answer to the comment:

If there characters, as you said one-character value(x, y, z or a, b, c it

doesn't really matter), in the RTYPE column, We can rewrite the CTE(the query in the WITH

clause) to generate set of characters as follows:

with rtypes(col) as(
  select chr(min_char + level - 1)
   from ( select max(ascii(rtype1)) as max_char
               , min(ascii(rtype1)) as min_char
            from test1
         ) 
 connect by min_char + level <=  max_char + 1
)

And then the final query will be:

with rtypes(col) as(
    select chr(min_char + level - 1)
      from ( select max(ascii(rtype1)) as max_char
                  , min(ascii(rtype1)) as min_char
              from test1
           ) 
   connect by min_char + level <=  max_char + 1
  )
select t.co_name
     , r.col                   as rtype
     , sum(nvl(some_count, 0)) as some_count
  from test1 t
  partition by (t.co_name)
  right join rtypes r
     on (r.col = t.rtype1)
  group by rollup(t.co_name, r.col)

Result:

Co_Name rtype   Some_Count
-------------------------------------- 
A       x       5 
A       y       6 
A       z       7 
A               18 
B       x       8 
B       y       9 
B       z       0 
B               17 
                35 

他のヒント

Okay this is the best I could do :)

It takes your existing query, and then unions in all non-existent combinations of co_name and rtype.

Same data:

create table test_rollup (
    co_name varchar2(100),
    rtype number,
    some_count number
)         ;

insert all
    into test_rollup (co_name, rtype, some_count) values ('A', 1, 5)
    into test_rollup (co_name, rtype, some_count) values ('A', 2, 6)
    into test_rollup (co_name, rtype, some_count) values ('A', 3, 7)
    into test_rollup (co_name, rtype, some_count) values ('B', 1, 8)
    into test_rollup (co_name, rtype, some_count) values ('B', 2, 9)
SELECT * FROM DUAL
;

select * from test_rollup;

Use WITH to define universal lists of co_name's and rtype's

WITH rtypes as 
(select distinct rtype from test_rollup
),
co_names as
(select distinct co_name from test_rollup
)
SELECT
    co_name,
    rtype,
    sum(some_count)
FROM test_rollup 
GROUP BY ROLLUP(co_name, rtype)    
[...]

And finally union in a cartesian join of the two universal lists, with their pairing defaulted to 0, minus and already-accounted-for combinations:

UNION
SELECT
    co_names.co_name,
    rtypes.rtype,
    0
FROM rtypes, co_names
where not exists 
  (select 1 
  from test_rollup 
  where test_rollup.co_name=co_names.co_name 
  and rtypes.rtype = test_rollup.rtype)
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top