Reputation: 1576
I have an Oracle table (Oracle 11g) that contains hours of overtime worked (WRK_HR) and the date worked (CHRG_DT). I want to build a stored procedure that returns the sum of WRK_HR for Saturday through Friday, each Friday, from the start of the project to the date provided. Say my table contains the following:
CHRG_DT WRK_HR
-------- ------
01/01/14 4
01/02/14 8
01/15/14 7
My output should look like this (each date is a Friday):
CHRG_DT TOTAL
-------- -----
01/03/14 12
01/10/14 12
01/17/14 19
Here is the SQL I have:
PROCEDURE GET_OVERTIME(
p_chrg_dt IN VARCHAR2,
cur OUT sys_refcursor
)
IS
BEGIN
OPEN cur FOR
SELECT
TO_CHAR(CHRG_DT, 'mm/dd/yyyy') AS CHRG_DT,
SUM(WRK_HR) AS TOTAL
FROM OVERTIME
WHERE TRUNC(CHRG_DT) <= TO_DATE(p_chrg_dt, 'mm/dd/yyyy')
GROUP BY CHRG_DT
ORDER BY CHRG_DT;
END;
Here is the result from my SQL. As you can see, it gives me a result for each unique day. I need it to total on every given Friday, even if there was no entry that Friday:
CHRG_DT TOTAL
-------- -----
01/01/14 4
01/02/14 12
01/15/14 19
Upvotes: 1
Views: 1992
Reputation: 40499
With this set of test data....
create table tq84_sum_data_by_week (
chrg_dt date,
wrk_hr number
);
insert into tq84_sum_data_by_week values (date '2014-01-01', 4);
insert into tq84_sum_data_by_week values (date '2014-01-02', 8);
insert into tq84_sum_data_by_week values (date '2014-01-15', 7);
... the following should do:
with fridays as (
--
-- 1 First, we need to "create" all fridays that we want
-- the report to sum on
--
select
--
-- 2 The first friday is 01/03/14
--
date '2014-01-03' +
--
-- 3 The fridays are 7 days apart:
--
(level-1) * 7 date_
--
from dual
--
-- 4 Three fridays are sufficient
-- for this small test.
--
connect by level <= 3
)
--
select
fridays.date_,
--
-- 7 This expression does the 'cumulative sum':
--
sum(sum(weeks.wrk_hr)) over (order by fridays.date_) total_hrs
from
--
-- 5 Since we want a record for *each* friday,
-- we use a 'left join':
--
fridays left outer join
--
tq84_sum_data_by_week weeks
--
-- 6 next_day(..., 'friday') returns the next
-- friday for a date which we need for the
-- join:
--
on fridays.date_ = next_day(weeks.chrg_dt, 'friday')
group by
fridays.date_;
Cleaning up:
drop table tq84_sum_data_by_week purge;
Same thing on SQL Fiddle
Upvotes: 1
Reputation: 52346
You just need to convert your day values to be the end-of-week, and select and group by that value.
Subtract one day from them, and use NEXT_DAY() to get the next friday ...
NEXT_DAY(CHRG_DT-1,'FRIDAY')
Upvotes: 3