Hello-
I need to create an output broken down by Account numbers and Locations.
Here is my sample table:
Create table sample_dat
(
POSITION_NO number (5),
NAME varchar2(50),
TITLE varchar2(50),
ACCOUNT number(15),
GAAP_ACNO number(15),
GAAP_DESC varchar2(50),
FUND varchar2(2),
BUDLOC varchar2(2),
TOT_SAL number(6),
FTE number(4),
STATUS varchar2(15),
LOC varchar2(50)
);
Here is my sample data set:
insert into sample_dat values(4985,'NAME','TITLE 1',1234,1234,'OTHER SALARIES','11','00',44074,1,'FILLED','01 GEORGE'):
insert into sample_dat values(4982,'NAME','TITLE 1',1234,1234,'OTHER SALARIES','11','00',49253,1,'FILLED','01 GEORGE'):
insert into sample_dat values(4543,'NAME','TITLE 1',1234,1234,'OTHER SALARIES','11','00',44074,1,'FILLED','01 GEORGE'):
insert into sample_dat values(5000,'NAME','TITLE 1',1234,1234,'OTHER SALARIES','11','00',42307,1,'FILLED','01 GEORGE'):
insert into sample_dat values(3113,'NAME ','TITLE 2',12341,12341,'TECH','11','00',0,1,'VACANT','01 GEORGE'):
insert into sample_dat values(1136,'NAME','TITLE 3',12341,12341,'TECH','11','01',9494,1,'FILLED','01 GEORGE'):
insert into sample_dat values(3839,'NAME','TITLE 5',12341,12341,'TECH','11','01',0,1,'VACANT','01 GEORGE'):
insert into sample_dat values(2688,'NAME','TITLE X',2345,2345,'INSTRUCTION','11','00',0,1,'VACANT','02 SCOTT'):
insert into sample_dat values(2724,'NAME','TITLE P',23451,23451,'PP','11','00',0,1,'VACANT','02 SCOTT'):
insert into sample_dat values(4245,'NAME','TITLE Q',23451,23451,'PP','11','00',0,1,'VACANT','02 SCOTT'):
insert into sample_dat values(3362,'NAME','TITLE 1',23451,23451,'PP','11','02',0,1,'FILLED','02 SCOTT'):
insert into sample_dat values(3295,'NAME','TITLE M',23452,23452,'SPORTS','11','02',57479,1,'FILLED','02 SCOTT'):
insert into sample_dat values(2443,'NAME','TITLE M',23452,23452,'SPORTS','11','02',56112,1,'FILLED','02 SCOTT'):
insert into sample_dat values(4144,'NAME','TITLE M',23452,23452,'SPORTS','11','02',56112,1,'FILLED','02 SCOTT'):
Expected output would be as shown:
POSITION_NO NAME TITLE ACCOUNT GAAP_ACNO GAAP_DESC FUND BUDLOC TOT_SAL FTE STATUS LOC
4985 NAME TITLE 1 1234 1234 OTHER SALARIES 11 00 44074 1 FILLED 01 GEORGE
4982 NAME TITLE 1 1234 1234 OTHER SALARIES 11 00 49253 1 FILLED 01 GEORGE
4543 NAME TITLE 1 1234 1234 OTHER SALARIES 11 00 44074 1 FILLED 01 GEORGE
5000 NAME TITLE 1 1234 1234 OTHER SALARIES 11 00 42307 1 FILLED 01 GEORGE
Account Total 179708 4
3113 NAME TITLE 2 12341 12341 TECH 11 00 0 1 VACANT 01 GEORGE
1136 NAME TITLE 3 12341 12341 TECH 11 01 9494 1 FILLED 01 GEORGE
3839 NAME TITLE 5 12341 12341 TECH 11 01 0 1 VACANT 01 GEORGE
Account Total 9494 3
Location Total 189202 7
2688 NAME TITLE X 2345 2345 INSTRUCTION 11 00 0 1 VACANT 02 SCOTT
Account Total 0 1
2724 NAME TITLE P 23451 23451 PP 11 00 0 1 VACANT 02 SCOTT
4245 NAME TITLE Q 23451 23451 PP 11 00 0 1 VACANT 02 SCOTT
3362 NAME TITLE 1 23451 23451 PP 11 02 0 1 FILLED 02 SCOTT
Account Total 0 3
3295 NAME TITLE M 23452 23452 SPORTS 11 02 57479 1 FILLED 02 SCOTT
2443 NAME TITLE M 23452 23452 SPORTS 11 02 56112 1 FILLED 02 SCOTT
4144 NAME TITLE M 23452 23452 SPORTS 11 02 56112 1 FILLED 02 SCOTT
Account Total 169703 3
Location Total 169703 6
District Total (Total of All Locations) 358905 13
I would assume this can be achieved using rollup/cube functions. However; not sure how to use these functions. Any
assistance would be appreciated!
Thanks
Venkat
Every unaggregated column in your select must appear in your group by.
But do this and you're aggregating at the most granular level. If you stick everything in a rollup or cube, you get subtotals for all the columns. You only want these rollups for (account, loc).
You could calculate all the subtotals. Then exclude all those you don't want. The grouping_id (...) function tells you which column you've got the subtotal for:
select POSITION_NO, NAME , TITLE , GAAP_ACNO , GAAP_DESC ,FUND ,BUDLOC , FTE ,STATUS,
ACCOUNT , LOC,
sum(TOT_SAL), count(*),
grouping_id (
loc, account, POSITION_NO, NAME , TITLE , GAAP_ACNO , GAAP_DESC ,FUND ,BUDLOC , FTE ,STATUS
) gid
from sample_dat
group by rollup(
loc, account, POSITION_NO, NAME , TITLE , GAAP_ACNO , GAAP_DESC ,FUND ,BUDLOC , FTE ,STATUS
);
POSITION_NO NAME TITLE GAAP_ACNO GAAP_DESC FUND BUDLOC FTE STATUS ACCOUNT LOC SUM(TOT_SAL) COUNT(*) GID
2688 NAME TITLE X 2345 INSTRUCTION 11 00 1 VACANT 2345 02 SCOTT 0 1 0
2688 NAME TITLE X 2345 INSTRUCTION 11 00 1 <null> 2345 02 SCOTT 0 1 1
2688 NAME TITLE X 2345 INSTRUCTION 11 00 <null> <null> 2345 02 SCOTT 0 1 3
2688 NAME TITLE X 2345 INSTRUCTION 11 <null> <null> <null> 2345 02 SCOTT 0 1 7
2688 NAME TITLE X 2345 INSTRUCTION <null> <null> <null> <null> 2345 02 SCOTT 0 1 15
2688 NAME TITLE X 2345 <null> <null> <null> <null> <null> 2345 02 SCOTT 0 1 31
2688 NAME TITLE X <null> <null> <null> <null> <null> <null> 2345 02 SCOTT 0 1 63
...<snip>...
But that's processing more data than you need to.
Luckily there's a way to get specific subgroups:
Grouping sets!
It seems you want four levels:
- All columns
- (Account, location) subtotals
- Location subtotals
- The grand total
The last three are a rollup of:
rollup ( location, account)
So stick this in grouping sets, along with another expression with every unaggregated column. Then use grouping_id to set a "total name" column:
with grps as (
select case grouping_id (account, loc, POSITION_NO)
when 1 then 'Account total'
when 5 then 'Location total'
when 7 then 'District total'
end grp,
POSITION_NO, NAME , TITLE , GAAP_ACNO , GAAP_DESC ,FUND ,BUDLOC , FTE ,STATUS,
ACCOUNT , LOC,
sum(TOT_SAL), count(*),
grouping_id (account, loc, POSITION_NO) gid
from sample_dat
group by grouping sets (
(POSITION_NO, NAME , TITLE , GAAP_ACNO , GAAP_DESC ,FUND ,BUDLOC , FTE ,STATUS, account, loc),
rollup(loc, account)
)
)
select * from grps
order by loc, account, gid;
GRP POSITION_NO NAME TITLE GAAP_ACNO GAAP_DESC FUND BUDLOC FTE STATUS ACCOUNT LOC SUM(TOT_SAL) COUNT(*) GID
<null> 5000 NAME TITLE 1 1234 OTHER SALARIES 11 00 1 FILLED 1234 01 GEORGE 42307 1 0
<null> 4985 NAME TITLE 1 1234 OTHER SALARIES 11 00 1 FILLED 1234 01 GEORGE 44074 1 0
<null> 4543 NAME TITLE 1 1234 OTHER SALARIES 11 00 1 FILLED 1234 01 GEORGE 44074 1 0
<null> 4982 NAME TITLE 1 1234 OTHER SALARIES 11 00 1 FILLED 1234 01 GEORGE 49253 1 0
Account total <null> <null> <null> <null> <null> <null> <null> <null> <null> 1234 01 GEORGE 179708 4 1
<null> 3113 NAME TITLE 2 12341 TECH 11 00 1 VACANT 12341 01 GEORGE 0 1 0
<null> 3839 NAME TITLE 5 12341 TECH 11 01 1 VACANT 12341 01 GEORGE 0 1 0
<null> 1136 NAME TITLE 3 12341 TECH 11 01 1 FILLED 12341 01 GEORGE 9494 1 0
Account total <null> <null> <null> <null> <null> <null> <null> <null> <null> 12341 01 GEORGE 9494 3 1
Location total <null> <null> <null> <null> <null> <null> <null> <null> <null> <null> 01 GEORGE 189202 7 5
<null> 2688 NAME TITLE X 2345 INSTRUCTION 11 00 1 VACANT 2345 02 SCOTT 0 1 0
Account total <null> <null> <null> <null> <null> <null> <null> <null> <null> 2345 02 SCOTT 0 1 1
<null> 2724 NAME TITLE P 23451 PP 11 00 1 VACANT 23451 02 SCOTT 0 1 0
<null> 3362 NAME TITLE 1 23451 PP 11 02 1 FILLED 23451 02 SCOTT 0 1 0
<null> 4245 NAME TITLE Q 23451 PP 11 00 1 VACANT 23451 02 SCOTT 0 1 0
Account total <null> <null> <null> <null> <null> <null> <null> <null> <null> 23451 02 SCOTT 0 3 1
<null> 3295 NAME TITLE M 23452 SPORTS 11 02 1 FILLED 23452 02 SCOTT 57479 1 0
<null> 4144 NAME TITLE M 23452 SPORTS 11 02 1 FILLED 23452 02 SCOTT 56112 1 0
<null> 2443 NAME TITLE M 23452 SPORTS 11 02 1 FILLED 23452 02 SCOTT 56112 1 0
Account total <null> <null> <null> <null> <null> <null> <null> <null> <null> 23452 02 SCOTT 169703 3 1
Location total <null> <null> <null> <null> <null> <null> <null> <null> <null> <null> 02 SCOTT 169703 7 5
District total <null> <null> <null> <null> <null> <null> <null> <null> <null> <null> <null> 358905 14 7