The best I have come up with so far with pure Oracle SQL is similar to what @AlexPoole did. I use count (A), not count (*), to put zeros at the bottom.
with NUM_ROWS_RETURNED as ( select 4 as NUM from dual ), SAMPLE_DATA as ( select A,B,C,D,E from ( select 1 as A, 1 as B, 4 as C, 1 as D, 4 as E from dual union all select 1 , -2 , 3 , 2 , 3 from dual union all select 1 , -2 , 2 , 2 , 3 from dual union all select null , 1 , 1 , 3 , 2 from dual union all select null , 2 , 4 , null , 2 from dual union all select null , 1 , 3 , null , 2 from dual union all select null , 1 , 2 , null , 1 from dual union all select null , 1 , 4 , null , 1 from dual union all select null , 1 , 3 , 3 , 1 from dual union all select null , 1 , 4 , 3 , 1 from dual ) ), RANKS as ( select rownum as RANKED from SAMPLE_DATA where rownum <= (select min(NUM) from NUM_ROWS_RETURNED) ) select r.RANKED, max(case when A_RANK = r.RANKED then A else null end) as A, max(case when B_RANK = r.RANKED then B else null end) as B, max(case when C_RANK = r.RANKED then C else null end) as C, max(case when D_RANK = r.RANKED then D else null end) as D, max(case when E_RANK = r.RANKED then E else null end) as E from ( select A, dense_rank() over (order by A_COUNTS desc) as A_RANK, B, dense_rank() over (order by B_COUNTS desc) as B_RANK, C, dense_rank() over (order by C_COUNTS desc) as C_RANK, D, dense_rank() over (order by D_COUNTS desc) as D_RANK, E, dense_rank() over (order by E_COUNTS desc) as E_RANK from ( select A, count(A) over (partition by A) as A_COUNTS, B, count(B) over (partition by B) as B_COUNTS, C, count(C) over (partition by C) as C_COUNTS, D, count(D) over (partition by D) as D_COUNTS, E, count(E) over (partition by E) as E_COUNTS from SAMPLE_DATA ) ) cross join RANKS r group by r.RANKED order by r.RANKED /
gives:
RANKED| A| B| C| D| E ------|----|----|----|----|---- 1| 1| 1| 4| 3| 1 2|null| -2| 3| 2| 2 3|null| 2| 2| 1| 3 4|null|null| 1|null| 4
with plan:
-------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 93 | 57 (20)| 00:00:01 | | 1 | TEMP TABLE TRANSFORMATION | | | | | | | 2 | LOAD AS SELECT | | | | | | | 3 | VIEW | | 10 | 150 | 20 (0)| 00:00:01 | | 4 | UNION-ALL | | | | | | | 5 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 6 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 7 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 8 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 9 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 10 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 11 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 12 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 13 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 14 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 15 | LOAD AS SELECT | | | | | | |* 16 | COUNT STOPKEY | | | | | | | 17 | VIEW | | 10 | | 2 (0)| 00:00:01 | | 18 | TABLE ACCESS FULL | SYS_TEMP_0FD9| 10 | 150 | 2 (0)| 00:00:01 | | 19 | SORT AGGREGATE | | 1 | | | | | 20 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 21 | SORT GROUP BY | | 1 | 93 | 33 (34)| 00:00:01 | | 22 | MERGE JOIN CARTESIAN | | 100 | 9300 | 32 (32)| 00:00:01 | | 23 | VIEW | | 10 | 800 | 12 (84)| 00:00:01 | | 24 | WINDOW SORT | | 10 | 800 | 12 (84)| 00:00:01 | | 25 | WINDOW SORT | | 10 | 800 | 12 (84)| 00:00:01 | | 26 | WINDOW SORT | | 10 | 800 | 12 (84)| 00:00:01 | | 27 | WINDOW SORT | | 10 | 800 | 12 (84)| 00:00:01 | | 28 | WINDOW SORT | | 10 | 800 | 12 (84)| 00:00:01 | | 29 | VIEW | | 10 | 800 | 7 (72)| 00:00:01 | | 30 | WINDOW SORT | | 10 | 150 | 7 (72)| 00:00:01 | | 31 | WINDOW SORT | | 10 | 150 | 7 (72)| 00:00:01 | | 32 | WINDOW SORT | | 10 | 150 | 7 (72)| 00:00:01 | | 33 | WINDOW SORT | | 10 | 150 | 7 (72)| 00:00:01 | | 34 | WINDOW SORT | | 10 | 150 | 7 (72)| 00:00:01 | | 35 | VIEW | | 10 | 150 | 2 (0)| 00:00:01 | | 36 | TABLE ACCESS FULL| SYS_TEMP_0FD9| 10 | 150 | 2 (0)| 00:00:01 | | 37 | BUFFER SORT | | 10 | 130 | 33 (34)| 00:00:01 | | 38 | VIEW | | 10 | 130 | 2 (0)| 00:00:01 | | 39 | TABLE ACCESS FULL | SYS_TEMP_0FD9| 10 | 130 | 2 (0)| 00:00:01 | -------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 16 - filter( (SELECT MIN(4) FROM "SYS"."DUAL" "DUAL")>=ROWNUM)
But with one of the real tables this looks (for a slightly modified query):
---------------------------------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop | TQ |IN-OUT| PQ Distrib | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 422 | | 6026M (1)|999:59:59 | | | | | | | 1 | TEMP TABLE TRANSFORMATION | | | | | | | | | | | | | 2 | LOAD AS SELECT | | | | | | | | | | | | |* 3 | COUNT STOPKEY | | | | | | | | | | | | | 4 | PX COORDINATOR | | | | | | | | | | | | | 5 | PX SEND QC (RANDOM) | :TQ10000 | 10 | | | 2 (0)| 00:00:01 | | | Q1,00 | P->S | QC (RAND) | |* 6 | COUNT STOPKEY | | | | | | | | | Q1,00 | PCWC | | | 7 | PX BLOCK ITERATOR | | 10 | | | 2 (0)| 00:00:01 | 1 | 115 | Q1,00 | PCWC | | | 8 | INDEX FAST FULL SCAN | IDX | 10 | | | 2 (0)| 00:00:01 | 1 | 115 | Q1,00 | PCWP | | | 9 | SORT GROUP BY | | 1 | 422 | | 6026M (1)|999:59:59 | | | | | | | 10 | MERGE JOIN CARTESIAN | | 22G| 8997G| | 6024M (1)|999:59:59 | | | | | | | 11 | VIEW | | 2289M| 872G| | 1443M (1)|999:59:59 | | | | | | | 12 | WINDOW SORT | | 2289M| 872G| 970G| 1443M (1)|999:59:59 | | | | | | | 13 | WINDOW SORT | | 2289M| 872G| 970G| 1443M (1)|999:59:59 | | | | | | | 14 | WINDOW SORT | | 2289M| 872G| 970G| 1443M (1)|999:59:59 | | | | | | | 15 | WINDOW SORT | | 2289M| 872G| 970G| 1443M (1)|999:59:59 | | | | | | | 16 | WINDOW SORT | | 2289M| 872G| 970G| 1443M (1)|999:59:59 | | | | | | | 17 | WINDOW SORT | | 2289M| 872G| 970G| 1443M (1)|999:59:59 | | | | | | | 18 | VIEW | | 2289M| 872G| | 248M (1)|829:16:06 | | | | | | | 19 | WINDOW SORT | | 2289M| 162G| 198G| 248M (1)|829:16:06 | | | | | | | 20 | WINDOW SORT | | 2289M| 162G| 198G| 248M (1)|829:16:06 | | | | | | | 21 | WINDOW SORT | | 2289M| 162G| 198G| 248M (1)|829:16:06 | | | | | | | 22 | WINDOW SORT | | 2289M| 162G| 198G| 248M (1)|829:16:06 | | | | | | | 23 | WINDOW SORT | | 2289M| 162G| 198G| 248M (1)|829:16:06 | | | | | | | 24 | WINDOW SORT | | 2289M| 162G| 198G| 248M (1)|829:16:06 | | | | | | | 25 | PARTITION RANGE ALL| | 2289M| 162G| | 3587K (4)| 11:57:36 | 1 | 115 | | | | | 26 | TABLE ACCESS FULL | LARGE_TABLE | 2289M| 162G| | 3587K (4)| 11:57:36 | 1 | 115 | | | | | 27 | BUFFER SORT | | 10 | 130 | | 6026M (1)|999:59:59 | | | | | | | 28 | VIEW | | 10 | 130 | | 2 (0)| 00:00:01 | | | | | | | 29 | TABLE ACCESS FULL | SYS_TEMP_0FD9| 10 | 130 | | 2 (0)| 00:00:01 | | | | | | ---------------------------------------------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - filter(ROWNUM<=10) 6 - filter(ROWNUM<=10)
I could use from LARGE_TABLE sample (0.01) to speed from LARGE_TABLE sample (0.01) up, despite the risk of getting a distorted image. That returned a 53-minute answer to a table with 2 billion rows.