SUBTOTALS of a GROUP BY IN ORACLE
up vote
1
down vote
favorite
This is the table I have.
TASK_CD | STATUS | DUE_DATE
----------------------------------
T0001 | NW | SYSDATE + 1
T0001 | IP | SYSDATE
T0001 | AG | SYSDATE
T0002 | NW | SYSDATE - 1
T0002 | NW | SYSDATE - 2
T0003 | AG | SYSDATE + 1
This is the query I have right now
select TASK_CD, STATUS, SUM(1) TOTALS,
SUM(CASE WHEN (TRUNC(DUE_DATE ) > SYSDATE) then 1 else 0 end) FUTURE,
SUM(CASE WHEN (TRUNC(DUE_DATE ) = SYSDATE) then 1 else 0 end) TODAY,
SUM(CASE WHEN (TRUNC(DUE_DATE ) < SYSDATE) then 1 else 0 end) OVERDUE,
FROM TM_TASK GROUP BY TASK_CD, STATUS;
result will be
TASK_CD | STATUS | TOTALS | FUTURE | TODAY | OVERDUE
----------------------------------------------------
T0001 | NW | 1 | 1 | 0 | 0
T0001 | IP | 1 | 0 | 1 | 0
T0001 | AG | 1 | 0 | 1 | 0
T0002 | NW | 2 | 0 | 0 | 2
T0003 | AG | 1 | 1 | 0 | 0
By removing STATUS from select and group, I get
TASK_CD | TOTALS | FUTURE | TODAY | OVERDUE
-----------------------------------------------
T0001 | 3 | 1 | 2 | 0
T0002 | 2 | 0 | 0 | 2
T0003 | 1 | 1 | 0 | 0
Is there a way to combine both and combine the results, giving me TOTALS_ALL, FUTURE_TOTALS, OVERDUE_TOTALS, TODAY_TOTALS where these are the sums when status is not considered for the GROUP BY
TASK_CD | STATUS | TOTALS | FUTURE | TODAY | OVERDUE| TOTALS_ALL | FUTURE_TOTAL | TODAY_TOTAL | OVERDUE_TOTAL
T0001 | NW | 1 | 1 | 0 | 0 | 3 | 1
| 2 | 0
T0001 | IP | 1 | 0 | 1 | 0 | 3 | 1
| 2 | 0
T0001 | AG | 1 | 0 | 1 | 0 | 3 | 1
| 2 | 0
T0002 | NW | 2 | 0 | 0 | 2 | 2 | 0
| 0 | 2
T0003 | AG | 1 | 1 | 0 | 0 | 1 | 1
| 0 | 0
sql oracle oracle11g
add a comment |
up vote
1
down vote
favorite
This is the table I have.
TASK_CD | STATUS | DUE_DATE
----------------------------------
T0001 | NW | SYSDATE + 1
T0001 | IP | SYSDATE
T0001 | AG | SYSDATE
T0002 | NW | SYSDATE - 1
T0002 | NW | SYSDATE - 2
T0003 | AG | SYSDATE + 1
This is the query I have right now
select TASK_CD, STATUS, SUM(1) TOTALS,
SUM(CASE WHEN (TRUNC(DUE_DATE ) > SYSDATE) then 1 else 0 end) FUTURE,
SUM(CASE WHEN (TRUNC(DUE_DATE ) = SYSDATE) then 1 else 0 end) TODAY,
SUM(CASE WHEN (TRUNC(DUE_DATE ) < SYSDATE) then 1 else 0 end) OVERDUE,
FROM TM_TASK GROUP BY TASK_CD, STATUS;
result will be
TASK_CD | STATUS | TOTALS | FUTURE | TODAY | OVERDUE
----------------------------------------------------
T0001 | NW | 1 | 1 | 0 | 0
T0001 | IP | 1 | 0 | 1 | 0
T0001 | AG | 1 | 0 | 1 | 0
T0002 | NW | 2 | 0 | 0 | 2
T0003 | AG | 1 | 1 | 0 | 0
By removing STATUS from select and group, I get
TASK_CD | TOTALS | FUTURE | TODAY | OVERDUE
-----------------------------------------------
T0001 | 3 | 1 | 2 | 0
T0002 | 2 | 0 | 0 | 2
T0003 | 1 | 1 | 0 | 0
Is there a way to combine both and combine the results, giving me TOTALS_ALL, FUTURE_TOTALS, OVERDUE_TOTALS, TODAY_TOTALS where these are the sums when status is not considered for the GROUP BY
TASK_CD | STATUS | TOTALS | FUTURE | TODAY | OVERDUE| TOTALS_ALL | FUTURE_TOTAL | TODAY_TOTAL | OVERDUE_TOTAL
T0001 | NW | 1 | 1 | 0 | 0 | 3 | 1
| 2 | 0
T0001 | IP | 1 | 0 | 1 | 0 | 3 | 1
| 2 | 0
T0001 | AG | 1 | 0 | 1 | 0 | 3 | 1
| 2 | 0
T0002 | NW | 2 | 0 | 0 | 2 | 2 | 0
| 0 | 2
T0003 | AG | 1 | 1 | 0 | 0 | 1 | 1
| 0 | 0
sql oracle oracle11g
Although it will not give you the same structure, as you've shown you expect, you could consider usingROLLUP
(or for more complex casesCUBE
) clause forGROUP BY
- it is designed to calculate totals and sub-totals.
– Hilarion
Nov 19 at 23:26
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
This is the table I have.
TASK_CD | STATUS | DUE_DATE
----------------------------------
T0001 | NW | SYSDATE + 1
T0001 | IP | SYSDATE
T0001 | AG | SYSDATE
T0002 | NW | SYSDATE - 1
T0002 | NW | SYSDATE - 2
T0003 | AG | SYSDATE + 1
This is the query I have right now
select TASK_CD, STATUS, SUM(1) TOTALS,
SUM(CASE WHEN (TRUNC(DUE_DATE ) > SYSDATE) then 1 else 0 end) FUTURE,
SUM(CASE WHEN (TRUNC(DUE_DATE ) = SYSDATE) then 1 else 0 end) TODAY,
SUM(CASE WHEN (TRUNC(DUE_DATE ) < SYSDATE) then 1 else 0 end) OVERDUE,
FROM TM_TASK GROUP BY TASK_CD, STATUS;
result will be
TASK_CD | STATUS | TOTALS | FUTURE | TODAY | OVERDUE
----------------------------------------------------
T0001 | NW | 1 | 1 | 0 | 0
T0001 | IP | 1 | 0 | 1 | 0
T0001 | AG | 1 | 0 | 1 | 0
T0002 | NW | 2 | 0 | 0 | 2
T0003 | AG | 1 | 1 | 0 | 0
By removing STATUS from select and group, I get
TASK_CD | TOTALS | FUTURE | TODAY | OVERDUE
-----------------------------------------------
T0001 | 3 | 1 | 2 | 0
T0002 | 2 | 0 | 0 | 2
T0003 | 1 | 1 | 0 | 0
Is there a way to combine both and combine the results, giving me TOTALS_ALL, FUTURE_TOTALS, OVERDUE_TOTALS, TODAY_TOTALS where these are the sums when status is not considered for the GROUP BY
TASK_CD | STATUS | TOTALS | FUTURE | TODAY | OVERDUE| TOTALS_ALL | FUTURE_TOTAL | TODAY_TOTAL | OVERDUE_TOTAL
T0001 | NW | 1 | 1 | 0 | 0 | 3 | 1
| 2 | 0
T0001 | IP | 1 | 0 | 1 | 0 | 3 | 1
| 2 | 0
T0001 | AG | 1 | 0 | 1 | 0 | 3 | 1
| 2 | 0
T0002 | NW | 2 | 0 | 0 | 2 | 2 | 0
| 0 | 2
T0003 | AG | 1 | 1 | 0 | 0 | 1 | 1
| 0 | 0
sql oracle oracle11g
This is the table I have.
TASK_CD | STATUS | DUE_DATE
----------------------------------
T0001 | NW | SYSDATE + 1
T0001 | IP | SYSDATE
T0001 | AG | SYSDATE
T0002 | NW | SYSDATE - 1
T0002 | NW | SYSDATE - 2
T0003 | AG | SYSDATE + 1
This is the query I have right now
select TASK_CD, STATUS, SUM(1) TOTALS,
SUM(CASE WHEN (TRUNC(DUE_DATE ) > SYSDATE) then 1 else 0 end) FUTURE,
SUM(CASE WHEN (TRUNC(DUE_DATE ) = SYSDATE) then 1 else 0 end) TODAY,
SUM(CASE WHEN (TRUNC(DUE_DATE ) < SYSDATE) then 1 else 0 end) OVERDUE,
FROM TM_TASK GROUP BY TASK_CD, STATUS;
result will be
TASK_CD | STATUS | TOTALS | FUTURE | TODAY | OVERDUE
----------------------------------------------------
T0001 | NW | 1 | 1 | 0 | 0
T0001 | IP | 1 | 0 | 1 | 0
T0001 | AG | 1 | 0 | 1 | 0
T0002 | NW | 2 | 0 | 0 | 2
T0003 | AG | 1 | 1 | 0 | 0
By removing STATUS from select and group, I get
TASK_CD | TOTALS | FUTURE | TODAY | OVERDUE
-----------------------------------------------
T0001 | 3 | 1 | 2 | 0
T0002 | 2 | 0 | 0 | 2
T0003 | 1 | 1 | 0 | 0
Is there a way to combine both and combine the results, giving me TOTALS_ALL, FUTURE_TOTALS, OVERDUE_TOTALS, TODAY_TOTALS where these are the sums when status is not considered for the GROUP BY
TASK_CD | STATUS | TOTALS | FUTURE | TODAY | OVERDUE| TOTALS_ALL | FUTURE_TOTAL | TODAY_TOTAL | OVERDUE_TOTAL
T0001 | NW | 1 | 1 | 0 | 0 | 3 | 1
| 2 | 0
T0001 | IP | 1 | 0 | 1 | 0 | 3 | 1
| 2 | 0
T0001 | AG | 1 | 0 | 1 | 0 | 3 | 1
| 2 | 0
T0002 | NW | 2 | 0 | 0 | 2 | 2 | 0
| 0 | 2
T0003 | AG | 1 | 1 | 0 | 0 | 1 | 1
| 0 | 0
sql oracle oracle11g
sql oracle oracle11g
edited Nov 19 at 20:35
Ben
40.6k2292118
40.6k2292118
asked Nov 19 at 19:49
Sitaram Vuppala
163
163
Although it will not give you the same structure, as you've shown you expect, you could consider usingROLLUP
(or for more complex casesCUBE
) clause forGROUP BY
- it is designed to calculate totals and sub-totals.
– Hilarion
Nov 19 at 23:26
add a comment |
Although it will not give you the same structure, as you've shown you expect, you could consider usingROLLUP
(or for more complex casesCUBE
) clause forGROUP BY
- it is designed to calculate totals and sub-totals.
– Hilarion
Nov 19 at 23:26
Although it will not give you the same structure, as you've shown you expect, you could consider using
ROLLUP
(or for more complex cases CUBE
) clause for GROUP BY
- it is designed to calculate totals and sub-totals.– Hilarion
Nov 19 at 23:26
Although it will not give you the same structure, as you've shown you expect, you could consider using
ROLLUP
(or for more complex cases CUBE
) clause for GROUP BY
- it is designed to calculate totals and sub-totals.– Hilarion
Nov 19 at 23:26
add a comment |
2 Answers
2
active
oldest
votes
up vote
2
down vote
You can use the subquery factoring clause (more commonly called a common table expresssion) to generate your initial data set and then an analytic SUM()
to aggregate
with initial_totals as (
select task_cd
, status
, count(*) as totals
, sum(case when due_date >= trunc(sysdate) + 1 then 1 else 0 end) as future
, sum(case when trunc(due_date) = trunc(sysdate) then 1 else 0 end) as today
, sum(case when due_date < trunc(sysdate) then 1 else 0 end) as overdue
from tm_task
group by task_cd, status
)
select task_cd
, status
, future
, today
, overdue
, sum(future) over (partition by task_cd) as future_total
, sum(today) over (partition by task_cd) as today_total
, sum(overdue) over (partition by task_cd) as overdue_total
from initial_totals
This is your original query (modified slightly see below) and then an analytic sum over each task code. An analytic sum is the same as an aggregate, but without putting the result against each row.
You can see this in action on db<>fiddle.
You'll note I've changed your date logic. This is because TRUNC(DUE_DATE ) > SYSDATE
is the same as saying when midnight today is greater than this second. I've changed this to due_date >= trunc(sysdate) + 1
, which is when this second is at or after midnight tomorrow. I've changed all the date logic in a similar manner.
It'd be beneficial to know, why the move ofTRUNC
can be good. For those cases, it'd also be good to show how to do the same for the current dayDUE_DATE
, not just past/future.
– Hilarion
Nov 19 at 23:33
Hi @Hilarion; to be honest that hurts a bit. You're criticising the correct answer with the explanation rather than the incorrect (not just dates the SQL logic too) without an explanation. I have explained why movingTRUNC()
is good as well as I know how. I haven't used the word "move" it's true, but it's not actually moving a function, it's a different logical construct. If you don't understand the explanation can you tell me what you don't understand so I can improve my explanation?
– Ben
Nov 20 at 6:03
Thank you @Ben. My only dilemma is which is a better approach your or Gordon. I tried doing the explain plan and the cost for both queries is similar. On running them both I time it was taking is similar as well. But my local db has limited test data. I have to see how they perform with huge loads.
– Sitaram Vuppala
Nov 20 at 14:50
They're basically the same query @Sitaram, I don't think there'll be any difference with large amouns of data. Have you checked that the data returned is correct in both? Either can be modified to return the correct data but it looks like we've interpreted your question slightly different.
– Ben
Nov 20 at 18:45
Yes, I was able to get the expected results...Thank you :)
– Sitaram Vuppala
Nov 20 at 18:46
|
show 1 more comment
up vote
2
down vote
You would use window functions:
select TASK_CD, STATUS, SUM(1) TOTALS,
SUM(CASE WHEN (TRUNC(DUE_DATE ) > SYSDATE) then 1 else 0 end) as FUTURE,
SUM(CASE WHEN (TRUNC(DUE_DATE ) = SYSDATE) then 1 else 0 end) as TODAY,
SUM(CASE WHEN (TRUNC(DUE_DATE ) < SYSDATE) then 1 else 0 end) as OVERDUE,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) > SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_FUTURE,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) = SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_TODAY,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) < SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_OVERDUE
FROM TM_TASK
GROUP BY TASK_CD, STATUS;
Hi, I have already tried partitioning, it was giving "ORA-00937: not a single-group group function" exception
– Sitaram Vuppala
Nov 19 at 22:42
2
Try it as @GordonLinoff described - it should work. Maybe you've missed the doubleSUM
use?
– Hilarion
Nov 19 at 23:27
Thank you @GordonLinoff. Yes I missed the double sum use.
– Sitaram Vuppala
Nov 20 at 14:33
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
You can use the subquery factoring clause (more commonly called a common table expresssion) to generate your initial data set and then an analytic SUM()
to aggregate
with initial_totals as (
select task_cd
, status
, count(*) as totals
, sum(case when due_date >= trunc(sysdate) + 1 then 1 else 0 end) as future
, sum(case when trunc(due_date) = trunc(sysdate) then 1 else 0 end) as today
, sum(case when due_date < trunc(sysdate) then 1 else 0 end) as overdue
from tm_task
group by task_cd, status
)
select task_cd
, status
, future
, today
, overdue
, sum(future) over (partition by task_cd) as future_total
, sum(today) over (partition by task_cd) as today_total
, sum(overdue) over (partition by task_cd) as overdue_total
from initial_totals
This is your original query (modified slightly see below) and then an analytic sum over each task code. An analytic sum is the same as an aggregate, but without putting the result against each row.
You can see this in action on db<>fiddle.
You'll note I've changed your date logic. This is because TRUNC(DUE_DATE ) > SYSDATE
is the same as saying when midnight today is greater than this second. I've changed this to due_date >= trunc(sysdate) + 1
, which is when this second is at or after midnight tomorrow. I've changed all the date logic in a similar manner.
It'd be beneficial to know, why the move ofTRUNC
can be good. For those cases, it'd also be good to show how to do the same for the current dayDUE_DATE
, not just past/future.
– Hilarion
Nov 19 at 23:33
Hi @Hilarion; to be honest that hurts a bit. You're criticising the correct answer with the explanation rather than the incorrect (not just dates the SQL logic too) without an explanation. I have explained why movingTRUNC()
is good as well as I know how. I haven't used the word "move" it's true, but it's not actually moving a function, it's a different logical construct. If you don't understand the explanation can you tell me what you don't understand so I can improve my explanation?
– Ben
Nov 20 at 6:03
Thank you @Ben. My only dilemma is which is a better approach your or Gordon. I tried doing the explain plan and the cost for both queries is similar. On running them both I time it was taking is similar as well. But my local db has limited test data. I have to see how they perform with huge loads.
– Sitaram Vuppala
Nov 20 at 14:50
They're basically the same query @Sitaram, I don't think there'll be any difference with large amouns of data. Have you checked that the data returned is correct in both? Either can be modified to return the correct data but it looks like we've interpreted your question slightly different.
– Ben
Nov 20 at 18:45
Yes, I was able to get the expected results...Thank you :)
– Sitaram Vuppala
Nov 20 at 18:46
|
show 1 more comment
up vote
2
down vote
You can use the subquery factoring clause (more commonly called a common table expresssion) to generate your initial data set and then an analytic SUM()
to aggregate
with initial_totals as (
select task_cd
, status
, count(*) as totals
, sum(case when due_date >= trunc(sysdate) + 1 then 1 else 0 end) as future
, sum(case when trunc(due_date) = trunc(sysdate) then 1 else 0 end) as today
, sum(case when due_date < trunc(sysdate) then 1 else 0 end) as overdue
from tm_task
group by task_cd, status
)
select task_cd
, status
, future
, today
, overdue
, sum(future) over (partition by task_cd) as future_total
, sum(today) over (partition by task_cd) as today_total
, sum(overdue) over (partition by task_cd) as overdue_total
from initial_totals
This is your original query (modified slightly see below) and then an analytic sum over each task code. An analytic sum is the same as an aggregate, but without putting the result against each row.
You can see this in action on db<>fiddle.
You'll note I've changed your date logic. This is because TRUNC(DUE_DATE ) > SYSDATE
is the same as saying when midnight today is greater than this second. I've changed this to due_date >= trunc(sysdate) + 1
, which is when this second is at or after midnight tomorrow. I've changed all the date logic in a similar manner.
It'd be beneficial to know, why the move ofTRUNC
can be good. For those cases, it'd also be good to show how to do the same for the current dayDUE_DATE
, not just past/future.
– Hilarion
Nov 19 at 23:33
Hi @Hilarion; to be honest that hurts a bit. You're criticising the correct answer with the explanation rather than the incorrect (not just dates the SQL logic too) without an explanation. I have explained why movingTRUNC()
is good as well as I know how. I haven't used the word "move" it's true, but it's not actually moving a function, it's a different logical construct. If you don't understand the explanation can you tell me what you don't understand so I can improve my explanation?
– Ben
Nov 20 at 6:03
Thank you @Ben. My only dilemma is which is a better approach your or Gordon. I tried doing the explain plan and the cost for both queries is similar. On running them both I time it was taking is similar as well. But my local db has limited test data. I have to see how they perform with huge loads.
– Sitaram Vuppala
Nov 20 at 14:50
They're basically the same query @Sitaram, I don't think there'll be any difference with large amouns of data. Have you checked that the data returned is correct in both? Either can be modified to return the correct data but it looks like we've interpreted your question slightly different.
– Ben
Nov 20 at 18:45
Yes, I was able to get the expected results...Thank you :)
– Sitaram Vuppala
Nov 20 at 18:46
|
show 1 more comment
up vote
2
down vote
up vote
2
down vote
You can use the subquery factoring clause (more commonly called a common table expresssion) to generate your initial data set and then an analytic SUM()
to aggregate
with initial_totals as (
select task_cd
, status
, count(*) as totals
, sum(case when due_date >= trunc(sysdate) + 1 then 1 else 0 end) as future
, sum(case when trunc(due_date) = trunc(sysdate) then 1 else 0 end) as today
, sum(case when due_date < trunc(sysdate) then 1 else 0 end) as overdue
from tm_task
group by task_cd, status
)
select task_cd
, status
, future
, today
, overdue
, sum(future) over (partition by task_cd) as future_total
, sum(today) over (partition by task_cd) as today_total
, sum(overdue) over (partition by task_cd) as overdue_total
from initial_totals
This is your original query (modified slightly see below) and then an analytic sum over each task code. An analytic sum is the same as an aggregate, but without putting the result against each row.
You can see this in action on db<>fiddle.
You'll note I've changed your date logic. This is because TRUNC(DUE_DATE ) > SYSDATE
is the same as saying when midnight today is greater than this second. I've changed this to due_date >= trunc(sysdate) + 1
, which is when this second is at or after midnight tomorrow. I've changed all the date logic in a similar manner.
You can use the subquery factoring clause (more commonly called a common table expresssion) to generate your initial data set and then an analytic SUM()
to aggregate
with initial_totals as (
select task_cd
, status
, count(*) as totals
, sum(case when due_date >= trunc(sysdate) + 1 then 1 else 0 end) as future
, sum(case when trunc(due_date) = trunc(sysdate) then 1 else 0 end) as today
, sum(case when due_date < trunc(sysdate) then 1 else 0 end) as overdue
from tm_task
group by task_cd, status
)
select task_cd
, status
, future
, today
, overdue
, sum(future) over (partition by task_cd) as future_total
, sum(today) over (partition by task_cd) as today_total
, sum(overdue) over (partition by task_cd) as overdue_total
from initial_totals
This is your original query (modified slightly see below) and then an analytic sum over each task code. An analytic sum is the same as an aggregate, but without putting the result against each row.
You can see this in action on db<>fiddle.
You'll note I've changed your date logic. This is because TRUNC(DUE_DATE ) > SYSDATE
is the same as saying when midnight today is greater than this second. I've changed this to due_date >= trunc(sysdate) + 1
, which is when this second is at or after midnight tomorrow. I've changed all the date logic in a similar manner.
answered Nov 19 at 20:28
Ben
40.6k2292118
40.6k2292118
It'd be beneficial to know, why the move ofTRUNC
can be good. For those cases, it'd also be good to show how to do the same for the current dayDUE_DATE
, not just past/future.
– Hilarion
Nov 19 at 23:33
Hi @Hilarion; to be honest that hurts a bit. You're criticising the correct answer with the explanation rather than the incorrect (not just dates the SQL logic too) without an explanation. I have explained why movingTRUNC()
is good as well as I know how. I haven't used the word "move" it's true, but it's not actually moving a function, it's a different logical construct. If you don't understand the explanation can you tell me what you don't understand so I can improve my explanation?
– Ben
Nov 20 at 6:03
Thank you @Ben. My only dilemma is which is a better approach your or Gordon. I tried doing the explain plan and the cost for both queries is similar. On running them both I time it was taking is similar as well. But my local db has limited test data. I have to see how they perform with huge loads.
– Sitaram Vuppala
Nov 20 at 14:50
They're basically the same query @Sitaram, I don't think there'll be any difference with large amouns of data. Have you checked that the data returned is correct in both? Either can be modified to return the correct data but it looks like we've interpreted your question slightly different.
– Ben
Nov 20 at 18:45
Yes, I was able to get the expected results...Thank you :)
– Sitaram Vuppala
Nov 20 at 18:46
|
show 1 more comment
It'd be beneficial to know, why the move ofTRUNC
can be good. For those cases, it'd also be good to show how to do the same for the current dayDUE_DATE
, not just past/future.
– Hilarion
Nov 19 at 23:33
Hi @Hilarion; to be honest that hurts a bit. You're criticising the correct answer with the explanation rather than the incorrect (not just dates the SQL logic too) without an explanation. I have explained why movingTRUNC()
is good as well as I know how. I haven't used the word "move" it's true, but it's not actually moving a function, it's a different logical construct. If you don't understand the explanation can you tell me what you don't understand so I can improve my explanation?
– Ben
Nov 20 at 6:03
Thank you @Ben. My only dilemma is which is a better approach your or Gordon. I tried doing the explain plan and the cost for both queries is similar. On running them both I time it was taking is similar as well. But my local db has limited test data. I have to see how they perform with huge loads.
– Sitaram Vuppala
Nov 20 at 14:50
They're basically the same query @Sitaram, I don't think there'll be any difference with large amouns of data. Have you checked that the data returned is correct in both? Either can be modified to return the correct data but it looks like we've interpreted your question slightly different.
– Ben
Nov 20 at 18:45
Yes, I was able to get the expected results...Thank you :)
– Sitaram Vuppala
Nov 20 at 18:46
It'd be beneficial to know, why the move of
TRUNC
can be good. For those cases, it'd also be good to show how to do the same for the current day DUE_DATE
, not just past/future.– Hilarion
Nov 19 at 23:33
It'd be beneficial to know, why the move of
TRUNC
can be good. For those cases, it'd also be good to show how to do the same for the current day DUE_DATE
, not just past/future.– Hilarion
Nov 19 at 23:33
Hi @Hilarion; to be honest that hurts a bit. You're criticising the correct answer with the explanation rather than the incorrect (not just dates the SQL logic too) without an explanation. I have explained why moving
TRUNC()
is good as well as I know how. I haven't used the word "move" it's true, but it's not actually moving a function, it's a different logical construct. If you don't understand the explanation can you tell me what you don't understand so I can improve my explanation?– Ben
Nov 20 at 6:03
Hi @Hilarion; to be honest that hurts a bit. You're criticising the correct answer with the explanation rather than the incorrect (not just dates the SQL logic too) without an explanation. I have explained why moving
TRUNC()
is good as well as I know how. I haven't used the word "move" it's true, but it's not actually moving a function, it's a different logical construct. If you don't understand the explanation can you tell me what you don't understand so I can improve my explanation?– Ben
Nov 20 at 6:03
Thank you @Ben. My only dilemma is which is a better approach your or Gordon. I tried doing the explain plan and the cost for both queries is similar. On running them both I time it was taking is similar as well. But my local db has limited test data. I have to see how they perform with huge loads.
– Sitaram Vuppala
Nov 20 at 14:50
Thank you @Ben. My only dilemma is which is a better approach your or Gordon. I tried doing the explain plan and the cost for both queries is similar. On running them both I time it was taking is similar as well. But my local db has limited test data. I have to see how they perform with huge loads.
– Sitaram Vuppala
Nov 20 at 14:50
They're basically the same query @Sitaram, I don't think there'll be any difference with large amouns of data. Have you checked that the data returned is correct in both? Either can be modified to return the correct data but it looks like we've interpreted your question slightly different.
– Ben
Nov 20 at 18:45
They're basically the same query @Sitaram, I don't think there'll be any difference with large amouns of data. Have you checked that the data returned is correct in both? Either can be modified to return the correct data but it looks like we've interpreted your question slightly different.
– Ben
Nov 20 at 18:45
Yes, I was able to get the expected results...Thank you :)
– Sitaram Vuppala
Nov 20 at 18:46
Yes, I was able to get the expected results...Thank you :)
– Sitaram Vuppala
Nov 20 at 18:46
|
show 1 more comment
up vote
2
down vote
You would use window functions:
select TASK_CD, STATUS, SUM(1) TOTALS,
SUM(CASE WHEN (TRUNC(DUE_DATE ) > SYSDATE) then 1 else 0 end) as FUTURE,
SUM(CASE WHEN (TRUNC(DUE_DATE ) = SYSDATE) then 1 else 0 end) as TODAY,
SUM(CASE WHEN (TRUNC(DUE_DATE ) < SYSDATE) then 1 else 0 end) as OVERDUE,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) > SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_FUTURE,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) = SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_TODAY,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) < SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_OVERDUE
FROM TM_TASK
GROUP BY TASK_CD, STATUS;
Hi, I have already tried partitioning, it was giving "ORA-00937: not a single-group group function" exception
– Sitaram Vuppala
Nov 19 at 22:42
2
Try it as @GordonLinoff described - it should work. Maybe you've missed the doubleSUM
use?
– Hilarion
Nov 19 at 23:27
Thank you @GordonLinoff. Yes I missed the double sum use.
– Sitaram Vuppala
Nov 20 at 14:33
add a comment |
up vote
2
down vote
You would use window functions:
select TASK_CD, STATUS, SUM(1) TOTALS,
SUM(CASE WHEN (TRUNC(DUE_DATE ) > SYSDATE) then 1 else 0 end) as FUTURE,
SUM(CASE WHEN (TRUNC(DUE_DATE ) = SYSDATE) then 1 else 0 end) as TODAY,
SUM(CASE WHEN (TRUNC(DUE_DATE ) < SYSDATE) then 1 else 0 end) as OVERDUE,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) > SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_FUTURE,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) = SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_TODAY,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) < SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_OVERDUE
FROM TM_TASK
GROUP BY TASK_CD, STATUS;
Hi, I have already tried partitioning, it was giving "ORA-00937: not a single-group group function" exception
– Sitaram Vuppala
Nov 19 at 22:42
2
Try it as @GordonLinoff described - it should work. Maybe you've missed the doubleSUM
use?
– Hilarion
Nov 19 at 23:27
Thank you @GordonLinoff. Yes I missed the double sum use.
– Sitaram Vuppala
Nov 20 at 14:33
add a comment |
up vote
2
down vote
up vote
2
down vote
You would use window functions:
select TASK_CD, STATUS, SUM(1) TOTALS,
SUM(CASE WHEN (TRUNC(DUE_DATE ) > SYSDATE) then 1 else 0 end) as FUTURE,
SUM(CASE WHEN (TRUNC(DUE_DATE ) = SYSDATE) then 1 else 0 end) as TODAY,
SUM(CASE WHEN (TRUNC(DUE_DATE ) < SYSDATE) then 1 else 0 end) as OVERDUE,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) > SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_FUTURE,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) = SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_TODAY,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) < SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_OVERDUE
FROM TM_TASK
GROUP BY TASK_CD, STATUS;
You would use window functions:
select TASK_CD, STATUS, SUM(1) TOTALS,
SUM(CASE WHEN (TRUNC(DUE_DATE ) > SYSDATE) then 1 else 0 end) as FUTURE,
SUM(CASE WHEN (TRUNC(DUE_DATE ) = SYSDATE) then 1 else 0 end) as TODAY,
SUM(CASE WHEN (TRUNC(DUE_DATE ) < SYSDATE) then 1 else 0 end) as OVERDUE,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) > SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_FUTURE,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) = SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_TODAY,
SUM(SUM(CASE WHEN (TRUNC(DUE_DATE ) < SYSDATE) then 1 else 0 end)) OVER (PARTITION BY status) as TOTAL_OVERDUE
FROM TM_TASK
GROUP BY TASK_CD, STATUS;
answered Nov 19 at 20:51
Gordon Linoff
748k34285391
748k34285391
Hi, I have already tried partitioning, it was giving "ORA-00937: not a single-group group function" exception
– Sitaram Vuppala
Nov 19 at 22:42
2
Try it as @GordonLinoff described - it should work. Maybe you've missed the doubleSUM
use?
– Hilarion
Nov 19 at 23:27
Thank you @GordonLinoff. Yes I missed the double sum use.
– Sitaram Vuppala
Nov 20 at 14:33
add a comment |
Hi, I have already tried partitioning, it was giving "ORA-00937: not a single-group group function" exception
– Sitaram Vuppala
Nov 19 at 22:42
2
Try it as @GordonLinoff described - it should work. Maybe you've missed the doubleSUM
use?
– Hilarion
Nov 19 at 23:27
Thank you @GordonLinoff. Yes I missed the double sum use.
– Sitaram Vuppala
Nov 20 at 14:33
Hi, I have already tried partitioning, it was giving "ORA-00937: not a single-group group function" exception
– Sitaram Vuppala
Nov 19 at 22:42
Hi, I have already tried partitioning, it was giving "ORA-00937: not a single-group group function" exception
– Sitaram Vuppala
Nov 19 at 22:42
2
2
Try it as @GordonLinoff described - it should work. Maybe you've missed the double
SUM
use?– Hilarion
Nov 19 at 23:27
Try it as @GordonLinoff described - it should work. Maybe you've missed the double
SUM
use?– Hilarion
Nov 19 at 23:27
Thank you @GordonLinoff. Yes I missed the double sum use.
– Sitaram Vuppala
Nov 20 at 14:33
Thank you @GordonLinoff. Yes I missed the double sum use.
– Sitaram Vuppala
Nov 20 at 14:33
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53381663%2fsubtotals-of-a-group-by-in-oracle%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Although it will not give you the same structure, as you've shown you expect, you could consider using
ROLLUP
(or for more complex casesCUBE
) clause forGROUP BY
- it is designed to calculate totals and sub-totals.– Hilarion
Nov 19 at 23:26