How to display weekly data for given date range - sql

I want to display all the data(count) between the given date range in week wise in oracle.
Select count(log.end_date)
from tablename
where log.end_date between '01-Jul-2013' AND '30-Jul-2013'
The date range can be between months also like - 01-Jun-2013 to 30-Jul-2013.
How can I display like this?
Count Week
23 wk1
45 wk2
67 wk3
34 wk4
78 wk5
and so on....
Thanks in advance

Have a look at this site and search for IW (ISO week)
You can alter your statement to be something like this:
SELECT count(log.end_date) Count,
to_char( date log.end_date, 'IW' ) Week
FROM tablename
WHERE log.end_date between '01-Jul-2013' AND '30-Jul-2013'
GROUP BY to_char( date log.end_date, 'IW' )
EDIT:
Did not take a part of the question into my query. Here is an updated version that substracts the ISO week of the first week and adds one to get wk1, wk2, wk3....
SELECT count(log.end_date) Count,
'wk' || (1 + to_char( date log.end_date, 'IW' ) - to_char( date '01-Jul-2013', 'IW')) Week
FROM tablename
WHERE log.end_date between '01-Jul-2013' AND '30-Jul-2013'
GROUP BY to_char( date log.end_date, 'IW' )

You are looking for to_char with either IW or WW format. You are also looking for the way to group by this week:
select count(*), to_char(end_date,'IW')
from tablename
where trunc(end_date) between to_date('01-07-2013','dd-mm-yyyy') and to_date('30-07-2013','dd-mm-yyyy')
group by to_char(end_date,'IW')
order by to_char(end_date,'IW');
From Oracle http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm:
IW Week of year (1-52 or 1-53) based on the ISO standard.
WW Week of year (1-53) where week 1 starts on the first day of the year and continues to the seventh day of the year.

Related

Exclude partial weeks from results BQ SQL

I am trying to find an easy way to exclude partial weeks from the results.
What I have so far:
WITH a AS (SELECT
FORMAT_DATE("%G-%V", created_date) as report_week
, created_date
, FORMAT_DATE('%A', created_date) AS day
, emp_id
, ROUND(SAFE_DIVIDE(SUM(working_time),3600),2) as hours
FROM `table1` a
WHERE created_date >= current_date()-10
GROUP BY 1,2,3,4,5)
SELECT
report_week
, emp_id
, hours
FROM a
WHERE day LIKE '%Monday%'
GROUP BY 1,2,3
ORDER BY report_week ASC
Input:
report_week: conversion of employee's shift date into week
created_date: date of employee's shift
day: conversion of date of employee's shift into day of week (Monday, Tuesday..)
emp_id: the employee's ID
hours: Number of worked hours by the employee
if current_date is 19 April 2022 then current_date()-10 is 9 April 2022.
Output:
The desired output is to return the number of hours worked for each employee during the full week 11 - 17 April only (it would exclude 9th, 10th, 18th and 19th of April from the results).
To obtain this, I tried to filter by having only week starting on a Monday with WHERE day LIKE '%Monday%' but in the example, it would also return the number of hours worked for each employee on 18th and 19th (since the 18th is a Monday). And if I combine this clause with AND (for example WHERE day LIKE '%Monday%' AND day LIKE '%Sunday%', it does not work at all.
Additionally, I see here another potential problem. If a Monday is a day off (like during Easter), then no employees will have hours on that Monday and the rest of the week will then not be returned.
My question: Is there an easy way to get only full weeks (Monday-Sunday) regardless the date range chosen?
Thank you in advance.
Best,
Fabien
You need to use UNNEST and create an array with a range of dates. Also, you need to use DATE_TRUNC to get the week and LAST_DAY to get the last day of the week. You can get the weeks that belong to each day in a range of dates.
You can see this example.
with sample_data as (
SELECT date FROM UNNEST(generate_timestamp_array('2022-04-09 00:00:00', '2022-04-19 00:00:00', INTERVAL 1 DAY)) as date
),
counting as(
select
DATE_ADD(DATE (date), INTERVAL 1 DAY) date
, DATE_TRUNC(DATE(date), WEEK)+1 week_start
, DATE_TRUNC(DATE(date), WEEK) +7 week_end
from sample_data
)
select b.date from (
select week_start,count(*) as ndays
from counting
group by week_start
having ndays=7
) a
join counting b on a.week_start=b.week_start
where timestamp(b.date) between timestamp(b.week_start) and timestamp(b.week_end)
I used the same range of dates like your example.

BigQuery extract week as date range from date field

I want to extract the week as date range from a DATETIME field in bigquery.
From these docs I can extract the week as a week number like this
EXTRACT(WEEK FROM date), or get the first day as date like this DATE_TRUNC(DATE(date), WEEK)
But what if I want to get a date range, for example if the date field have the value 2021-12-23 04:30:00 and say Sunday is the first the of the week, I would like to get this result 2021-12-19 - 2021-12-25
or something similar. Is it possible?
Depending on your desired output, separate columns or single string, you can try the following:
with sample_data as (
SELECT date FROM UNNEST(generate_timestamp_array('2021-12-01 00:00:00', '2022-02-01 00:00:00', INTERVAL 1 DAY)) as date
)
select
date
, DATE_TRUNC(DATE(date), WEEK) week_start
, DATE_TRUNC(DATE(date), WEEK) +6 week_end
, LAST_DAY(DATE(date), WEEK) as alt_week_end
, concat(DATE_TRUNC(DATE(date), WEEK)," - ", DATE_TRUNC(DATE(date), WEEK) +6) week_range
from sample_data
Consider below approach
select *,
date_trunc(date(date), week) week_start,
last_day(date(date), week) week_end
from your_table
with output like

getting last day from next month

I need to get last day from next month in this select.
select (last_day(month from :date+1)||'.'||
(extract(month from :date)+1)||'.'||
extract(year from :date))
from dual;
Everything is ok with month and year but I have a problem with last day function.
Using (extract(month from :date)+1) will not work for a date in December as you will end up with a 13th month. Similarly, extract(year from :date) will get you the current year - which may not be correct if you are looking for the last day of the next month from December and the result should be the January of the following year.
You do not need to extract all the fields separately, you can do it all in a single statement:
SELECT TO_CHAR(
LAST_DAY( ADD_MONTHS( :date, 1 ) ),
'DD.MM.YYYY'
)
FROM DUAL

Given a date, select all the week numbers that month contains

I have an ApEx application for tracking working hours.
I have a view that looks like this:
CREATE OR REPLACE VIEW HOURSDAYS
AS SELECT
(MAX("TO_X") - MIN("FROM_X"))*24 -
(max(case when PROJECT_ID = 999 then to_x else to_date('01012000','DDMMYYYY') end) -
max(case when PROJECT_ID = 999 then from_x else to_date('01012000','DDMMYYYY') end))*24 AS TIME_SPENT,
DAY,
PERSON_ID
FROM ATTENDANCE_HOURS
GROUP BY PERSON_ID, DAY
ORDER BY DAY DESC
I need the sum of hours per week. So I have this:
SELECT TO_CHAR(DAY,'IW'), MIN(DAY), MAX(DAY), SUM(TIME_SPENT)
FROM HOURSDAYS
WHERE PERSON_ID = (SELECT ID FROM ATTENDANCE_PEOPLE WHERE MAIL_SSO = V('APP_USER') AND ROLE = 0) AND
EXTRACT (YEAR FROM DAY) = EXTRACT (YEAR FROM TO_DATE(:P100_DATE_PICKER,'DD-MON-RR'))
GROUP BY TO_CHAR(DAY,'IW')
ORDER BY TO_CHAR(DAY,'IW') ASC
And now the fun begins: I have a page item P100_DATE_PICKER and I need to display only those weeks that have > 0 days that belong to the month to which belongs the day I've picked using the date picker.
For example, for 1.1.2015 I want only weeks 1, 2, 3, 4, 5 displayed. 24.3.2015: 9, 10, 11, 12, 13, 14.
If anyone is interested in why would I do that, it is for validation - number of work hours per week cannot exceed 20/32, depends on what type of contract do you have.
You can do like this:
where day >= trunc(trunc(TO_DATE(:P100_DATE_PICKER,'DD-MON-RR'), 'MM'),'IW')
and day < trunc(last_day(TO_DATE(:P100_DATE_PICKER,'DD-MON-RR')),'IW') + 7
The first line starts by trunc to MM, which gives you the first day of the month of your date. Then trunc again to IW gives you the date of the monday in the week that contains the first day of month.
The second line uses last_day to get the last day of the month of your date. Then trunc to IW gets the monday of that week, and adding 7 days get the monday after. Then by using < rather than <= you get the desired result.
Also I suggest you do not group and order by TO_CHAR(DAY,'IW') but instead use TRUNC(DAY,'IW') for your grouping and ordering. Otherwise you can get into problems around new year, because your code for example when showing the weeks for December 2014 would have to show 49 to 52 of year 2014 as well as week 1 of year 2015. If you use TO_CHAR that week 1 would be wrongly sorted before weeks 49 to 52.
Similarly do not use EXTRACT(YEAR FROM ...) or even TO_CHAR(...,'YYYY') when you are working with ISO weeks. Because the date '2014-12-31' belongs to ISO week 1 year 2015, there is a special date format string 'IYYY' which gives the correct year for the ISO week. Try it out and see the difference between 'YYYY' and 'IYYY'.
This will not answer all your questions. This is the quick example of week calculation from a given date according to the subject line of your question. Pls copy/paste to see results. Also, here's the link to check the week numbers:
http://www.epochconverter.com/date-and-time/weeknumbers-by-year.php
SELECT given_date
, end_date
, TRUNC(calc_start_date, 'iw') wk_starts
, TRUNC(calc_start_date, 'iw') + 7 - 1/86400 wk_ends
, TO_CHAR(calc_start_date, 'iw') wk_number
, calc_start_date
FROM
(
SELECT trunc(sysdate, 'mm') given_date
, trunc(sysdate, 'mm')-7 + LEVEL*7 AS calc_start_date
, Last_Day(trunc(SYSDATE, 'mm')) end_date
FROM dual
CONNECT BY LEVEL <= ROUND((trunc(last_day(sysdate)) - trunc(sysdate, 'mm')+7)/7) -- number of weeks --
)
/
GIVEN DATE END DATE WK_STARTS WK_ENDS WK NUMBER
-------------------------------------------------------------------------
1/1/2015 1/31/2015 12/29/2014 1/4/2015 11:59:59 PM 01
1/1/2015 1/31/2015 1/5/2015 1/11/2015 11:59:59 PM 02
1/1/2015 1/31/2015 1/12/2015 1/18/2015 11:59:59 PM 03
1/1/2015 1/31/2015 1/19/2015 1/25/2015 11:59:59 PM 04
1/1/2015 1/31/2015 1/26/2015 2/1/2015 11:59:59 PM 05
The best way to achieve the last part is to have a calendar table that has the following columns
Date, Day eg Mon, Month, Quarter, Year, WeekNo
Then for a given date you can simply select all the weeks that belong to the month.
This allows you to define weekNo so that it fits in with company circumstances. Eg occasionally you may get a 53 week year, especially if they operate 4-4-5 accounting periods
with days as (
select
to_number(to_char(trunc(to_date('2015-03-24', 'yyyy-MM-dd'), 'month'), 'WW')) w1,
to_number(to_char(last_day(to_date('2015-03-24', 'yyyy-MM-dd')), 'WW')) w2
from dual)
select w1+level-1 week from days
connect by level <= w2-w1+1
Subquery days gives minimum and maximum week, query with connect by returns numbers between these values. Please replace example date with :P100_DATE_PICKER.

select records weekly from Oracle table

I need to select recods from oracle table for the current calendar week based on a date datatype field. Currently I am doing like this:
select * from my_table where enter_date > sysdate -7
If today is Thursday, this query will select records seven days from today which infiltrates to last week on Thursday. Is there a way to select records for the current calendar week dynamically?
If your week starts on a Monday then:
select ...
from ...
where dates >= trunc(sysdate,'IW')
For alternative definitions of the first day of the week, trunc(sysdate,'W') truncates to the day of the week with which the current month began, and trunc(sysdate,'WW') truncates to the day of the week with which the current year began.
See other available truncations here: http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions255.htm#i1002084
to_char(sysdate, 'd') returns day of week in [1..7] range; so try using
select *
from my_table
where enter_date >= trunc(sysdate) - to_char(sysdate, 'd') + 1
Here is the SQLFiddel Demo
Below is the query which you can try
select Table1.*
from Table1
where dates > sysdate - TO_CHAR(SYSDATE,'D')