PL/SQL weekly Aggregation Logic with dynamic time range - oracle

I need to aggregate the values at weekly interval. My date range is dynamic means i can give any start date and end date. Every sunday should be the starting week of every month. say if i have two columns and my start and end date is 07/11/2016 to 13/11/2016
column A column B
07/11/2016 23
08/11/2016 20
09/11/2016 10
10/11/2016 05
11/11/2016 10
12/11/2016 20
13/11/2016 10
My result should come like taking the average of column B
Column A Column B
13/11/2016 14.00
It means i should consider the past value and aggregate it to the day Sunday of that week. Also if my start and end date is like 07/11/2016 to 10/11/2016 then I should not aggregate the value as my week is not complete. I am able to aggregate the values but if my week is not complete i m not able to restrict the aggregation.
Is there any way to do this in PL/SQL??
Thank you in advance.

select to_char(columnA, 'iw') as weeknumber, avg(columnB)
from table
group by to_char(columnA, 'iw');
This will aggregate by number of week. If you need to show last day of week as a label you can get it as max(columnA) over (partition by to_char(columnA, 'iw'))

Related

Google sheet formula to return sum based on multiple criteria using input cells

I have rows of dates with tasks measured in hours. These tasks are assigned to different team leaders whose names are also included on each row. I would like create a multiple criteria Google sheet formula that returns the sum of hours based on the date range and the name of the team leader.
These are the data input cells I would be entering to produce the sum:
Date Start:
Date End:
Team Leader Name:
Ideally if the Team Leader name was not entered, the formula would sum the hours for all of the rows selected by the date range.
Here are some sample rows:
Job Date
Hours
Team Leader
03/25/2022
8
John
04/22/2022
7
Hannah
04/23/2022
6
John
05/01/2022
6
Hannah
Thank you in advance for your help with this!
Assuming you have the following
A:C - Job Date, Hours, Team Leader
D1 - Start Date
D2 - End Date
D3 - Team Leader
=QUERY(
{A1:C},
"select Sum(Col2)
where
Col1 >= date '"&TEXT(IF(ISBLANK(D1),DATE(1970,1,1),D1),"yyyy-mm-dd")&"' and
Col1 <= date '"&TEXT(IF(ISBLANK(D2),DATE(3000,1,1),D2),"yyyy-mm-dd")&"' and
Col3 matches '"&IF(ISBLANK(D3),".*",D3)&"'
label Sum(Col2) ''")
If the start or end dates are blank, it reverts to extreme dates. For Col3 it is using REGEX -- if D3 is blank, it reverts to a wildcard and will return everything summed up.
You can use SUMIFS() function like-
=SUMIFS(B2:B,A2:A,">="&E2,A2:A,"<="&F2,C2:C,IF(G2="","*",G2))

Oracle - determine and return the specfic hour of data with the highest sum of the values

I think I can do this in a more roundabout way using arrays, scripting, etc...BUT is it possible to sum up (aggregate) all the values for each "hour" of data in a database for a given field? Basically, I am trying to determine which hour in a day's worth of data had the highest sum...preferably without having to loop through 24 times for each day I want to look at. For example...let's say I have a table called "table", that contains columns for times and values as the follows:
Time Value
00:00 1
00:15 1
00:30 2
00:45 2
01:00 1
01:15 1
01:30 1
01:45 1
If I summed up by hand, I would get the following
Sum for 00 Hour = 6
Sum for 01 Hour = 4
So, in this example 00 Hour would be my "largest sum" hour. I'd like to end up returning simply which hour had the highest sum, and what that value was...the other hours don't matter in this case.
Can this be done all in a single ORACLE query, or does it need to be done outside the query with some scripting and working with the times and values separately? If not a single, maybe even just grab the sum for each hour, and I can run multiple queries - one for each hour? Then push each hour to an array, and just use the max of that array? I know there is a SUM() function in oracle, but how to tell it to "sum all the hours and just return the hour with the highest sum" escapes me. Hope all this makes sense. lol
Thanks for any advice to make this easier. :-)
The following query should do what you are looking for:
SELECT SUBSTR(time, 1, 2) AS HOUR,
SUM(amount) AS TOTAL_AMOUNT
FROM test_data
GROUP BY SUBSTR(time, 1, 2)
ORDER BY TOTAL_AMOUNT DESC
FETCH FIRST ROW WITH TIES;
The query uses the SUM function but grouping by the hour part of your time column. Then it orders the results by the summed amounts descending, only returning the maximum value.
Here is a DBFiddle showing the query in use (LINK)

select unique trunc(sysdate-370 + level, 'IW') AS datetime from dual connect by level <= 360 order by datetime

Can someone explain me what does the below oracle query do and what is it's output?
select unique trunc(sysdate-370 + level, 'IW') AS datetime from dual
connect by level <= 360 order by datetime;
select sysdate-370 + level AS datetime
from dual
connect by level <= 360;
Will generate 360 rows starting with the current date/time minus 370 days plus one day per row. So rows between 369 and 10 days before the current date/time.
TRUNC( datetime, 'IW' ) will truncate the date to the start of the ISO week (midnight on Monday of that week - irrespective of the NLS settings for date language and/or territory that affect some other options for truncating dates). So you will end up with duplicate rows for each generated row that is in the same week.
The UNIQUE keyword will get rid of those duplicate rows.
The order by datetime will order the results in ascending date order - however, the rows are generated in ascending order so this clause is unnecessary.
So the output will be 52 or 53 rows (depending on what the current day of the week is) starting with Monday midnight of each week containing the date 369 days before the current day up until the week containing 10 days before the current date.
The output (when run on 13th September 2017) is 52 rows (I skipped a few):
05-SEP-2016
12-SEP-2016
19-SEP-2016
26-SEP-2016
03-OCT-2016
...
31-JUL-2017
07-AUG-2017
14-AUG-2017
21-AUG-2017
28-AUG-2017
According to documentation trunc(dateval, 'IW') truncates to:
Same day of the week as the first day of the calendar week as defined by the ISO 8601 standard, which is Monday
connect by level <= N is a trick for producing a set of N rows with level values from 1 to N.

Oracle - Show 0 if no data for the month

i'm trying to show some averages over the past 12 months but there is no data for June/July so i want the titles for the months to display but just 0's in the 3 columns
currently it's only showing August - May which is 10 rows so it's throwing off formulas and charts etc.
select to_char(Months.Period,'YYYY/MM') As Period, coalesce(avg(ec.hours_reset),0) as AvgOfHOURSReset, coalesce(AVG(ec.cycles_reset),0) as AvgofCycles_Reset, Coalesce(AVG(ec.days_reset),0) as AvgofDAYS_Reset
from (select distinct reset_date as Period from engineering_compliance
where reset_date between '01/JUN/15' and '31/MAY/16') Months
left outer join engineering_compliance ec on ec.reset_date = months.Period
WHERE EC.EO = 'AT CHECK'
group by to_char(Months.Period,'YYYY/MM')
order by to_char(Months.Period,'YYYY/MM')
;
(select distinct to_char(reset_date,'YYYY/MM') as Period from engineering_compliance
where reset_date between '01/JUN/15' and '31/MAY/16') Months;
That query is pretty good, it's not far from working.
You would need to replace the Months table part. You want exactly one row per month, regardless of whether there's any data in the ec table.
You could maybe synthesize some data without going to any actual table in your own schema.
For example:
SELECT
extract(month from add_months(sysdate,level-1)) Row_Month,
extract(year from add_months(sysdate,level-1)) Row_Year,
to_char(add_months(sysdate,level-1),'YYYY/MM') Formatted_Date,
trunc(add_months(sysdate,level-1),'mon') Join_Date
FROM dual
CONNECT BY level <= 12;
gives:
ROW_MONTH,ROW_YEAR,FORMATTED_DATE,JOIN_DATE
6,2016,'2016/06',1/06/2016
7,2016,'2016/07',1/07/2016
8,2016,'2016/08',1/08/2016
9,2016,'2016/09',1/09/2016
10,2016,'2016/10',1/10/2016
11,2016,'2016/11',1/11/2016
12,2016,'2016/12',1/12/2016
1,2017,'2017/01',1/01/2017
2,2017,'2017/02',1/02/2017
3,2017,'2017/03',1/03/2017
4,2017,'2017/04',1/04/2017
5,2017,'2017/05',1/05/2017
Option 1: Write that subselect inline into your query, replacing sysdate with the start month and the figure 12 on the last line can be altered for the number of months you want in the series.
Option 2 (can be reused more conveniently in a variety of situations and queries): Write a view with a long series of months (for example, Jan 1970 to Dec 2199) using my SQL above. You can then join to that view on join_date with whatever start and end months you want. It will give you one row per month and you can pick up the formatted date from its column.

Oracle SQL group by week /month

How can we group reocrds weekly/monthly in oracle between from date and to date so that one record can be returned for one week/month.
e.g If we have 5 records for Ist weeek and 3 records for second week between a from date and to date then it should return total 2 records(one for Ist week and one for second week).
Thanks in advance.
You can group the results using GROUP BY: http://www.techonthenet.com/oracle/group_by.php
To select only those between from date and to date use WHERE
EDIT
For selecting the begining of the week or month, you can use TRUNC(the_date_field, ): http://www.techonthenet.com/oracle/functions/trunc_date.php
For example this groups by week:
SELECT TRUNC(datecol_name, 'WW') FROM table_name GROUP BY TRUNC(datecol_name, 'WW');

Resources