SQL Server select missing Dates in result set - sql

I have one table containing Employee Daily Attendance punchtime in space separated form.
EmployeePunch
EmpID EmpName Date Time
1 ABC 2014-12-01 10:00 18:00
1 ABC 2014-12-02 09:50 17:50
1 ABC 2014-12-04 09:30 17:30
1 ABC 2014-12-07 10:00 18:00
1 ABC 2014-12-08 09:50 17:50
1 ABC 2014-12-10 09:30 17:30
Now I want to write a query for following output
EmpID EmpName Date Time
1 ABC 2014-12-01 10:00 18:00
1 ABC 2014-12-02 09:50 17:50
1 ABC 2014-12-03 ABSENT
1 ABC 2014-12-04 09:30 17:30
1 ABC 2014-12-05 ABSENT
1 ABC 2014-12-06 ABSENT
1 ABC 2014-12-07 10:00 18:00
1 ABC 2014-12-08 09:50 17:50
1 ABC 2014-12-09 ABSENT
1 ABC 2014-12-10 09:30 17:30

First define CTE to generate missing records:
WITH dates AS (
SELECT DISTINCT EmpId, EmpName, '2014-12-01' AS Date, 'ABSENT' AS Time
FROM EmployeePunch
UNION
SELECT EmpId, EmpName, DATEADD(DAY, 1, Date), 'ABSENT'
FROM dates
WHERE Date < DATEADD(DAY, -1, DATEADD(MONTH, 1, '2014-12-01')))
SELECT * FROM dates
In the next step replace the last line with:
SELECT * FROM EmployeePunch
UNION ALL
SELECT d.* FROM dates d
LEFT JOIN EmployeePunch e
ON e.EmpId = d.EmpId AND e.Date = d.Date
WHERE e.Time IS NULL
The missing rows are the outerjoined ones.

Without CTE:
select ep1.EmpId, ep1.EmpName, a.Date, ISNULL(ep2.Time, 'ABSENT') as Time
from (
select DATEADD(day, a.a + (10 * b.a) + (100 * c.a), CAST('2014-12-01' /*begin date*/ AS DATE)) as Date
from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) a cross apply (select distinct EmpId, EmpName from EmployeePunch) ep1 --on a.Date = f.Date
left join EmployeePunch ep2 on ep2.Date = a.Date and ep2.EmpId = ep1.EmpId
where a.Date <= '2014-12-10' and ep1.EmpId is not null
Be aware about the maximal allowed range - 1000 days, but it can be extended if necessary

Related

SQL Start Date and End Date Matching

I have one table that contains customer id and start date and one table that contains customer id and end date.
table A
customer_id
start_date
1
2022-01-01
1
2022-04-01
1
2022-07-01
2
2022-01-15
2
2022-03-25
3
2022-04-01
3
2022-08-01
4
2022-09-01
table B
customer_id
end_date
1
2022-01-25
1
2022-05-03
2
2022-03-24
2
2022-03-29
3
2022-04-15
Is there a way that I can get an output that looks like below?
desired output
customer_id
start_date
end_date
1
2022-01-01
2022-01-25
1
2022-04-01
2022-05-03
1
2022-07-01
2
2022-01-15
2022-03-24
2
2022-03-25
2022-03-29
3
2022-04-01
2022-04-15
3
2022-08-01
4
2022-09-01
As per your desire result please check the below query you can change it as per your table name and requirements.
DECLARE #table1 TABLE(
[customer_id] INT,
[start_date] DATE
)
DECLARE #table2 TABLE(
[customer_id] INT,
[end_date] DATE
)
INSERT INTO #table1 VALUES
(1,'2022-01-01'),
(1,'2022-04-01'),
(1,'2022-07-01'),
(2,'2022-01-15'),
(2,'2022-03-25'),
(3,'2022-04-01'),
(3,'2022-08-01'),
(4,'2022-09-01')
INSERT INTO #table2 VALUES
(1,'2022-01-25'),
(1,'2022-05-03'),
(2,'2022-03-24'),
(2,'2022-03-29'),
(3,'2022-04-15')
SELECT [Table1].[customer_id],[Table1].[start_date],[Table2].[end_date] FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY [start_date]) row_num FROM #table1
) AS [Table1]
LEFT JOIN (
SELECT t2.*, ROW_NUMBER() OVER (ORDER BY [end_date] ) row_num FROM #table2 t2
) AS [Table2]
ON [Table2].[customer_id] = [Table1].[customer_id]
AND [Table1].[row_num] = [Table2].[row_num]
ORDER BY [Table1].[customer_id]
Output
This hint is using TSQL in SQL Server.
select A.customer_id, A.start_date, B.end_date
from
(select X.costumer_id, X.start_date, ROW_NUMBER() over (order by X.start_date) as ORDEM from TableA X) A
left outer join (select X.customer_id, X.end_date, ROW_NUMBER() over (order by X.end_date ) as ORDEM from TableB X) B on A.customer_id = B.customer_id and A.ORDEM = B.ORDEM
order by A.customer_id, A.start_date
Hope it helps.
Here is how it's done in Vertica 12 - now that we have INTERPOLATE NEXT VALUE for the event series join :
\pset null (null)
WITH
tba(customer_id,start_date) AS (
SELECT 1,DATE '2022-01-01'
UNION ALL SELECT 1,DATE '2022-04-01'
UNION ALL SELECT 1,DATE '2022-07-01'
UNION ALL SELECT 2,DATE '2022-01-15'
UNION ALL SELECT 2,DATE '2022-03-25'
UNION ALL SELECT 3,DATE '2022-04-01'
UNION ALL SELECT 3,DATE '2022-08-01'
UNION ALL SELECT 4,DATE '2022-09-01'
)
,
tbb(customer_id,end_date) AS (
SELECT 1,DATE '2022-01-25'
UNION ALL SELECT 1,DATE '2022-05-03'
UNION ALL SELECT 2,DATE '2022-03-24'
UNION ALL SELECT 2,DATE '2022-03-29'
UNION ALL SELECT 3,DATE '2022-04-15'
)
SELECT
tba.customer_id
, start_date
, end_date
FROM tba
LEFT JOIN tbb
ON tba.customer_id = tbb.customer_id
AND end_date INTERPOLATE NEXT VALUE start_date
ORDER BY 1,2
;
-- out Null display is "(null)".
-- out customer_id | start_date | end_date
-- out -------------+------------+------------
-- out 1 | 2022-01-01 | 2022-01-25
-- out 1 | 2022-04-01 | 2022-05-03
-- out 1 | 2022-07-01 | (null)
-- out 2 | 2022-01-15 | 2022-03-24
-- out 2 | 2022-03-25 | 2022-03-29
-- out 3 | 2022-04-01 | 2022-04-15
-- out 3 | 2022-08-01 | (null)
-- out 4 | 2022-09-01 | (null)

Pull out most non overlapping date range

Sorry, going to start over and try to explain from the start:
I have a small list of dates:
date mark
08-16-2016 1
08-17-2016 1
01-03-2017 1
02-16-2018 1
02-17-2018 1
From here I need to find out in a 3 year period if there is 2 continuous years where there are less than 3 marks. I'm looking over a date range from 2016-08-01 to 2019-08-01.
So I setup the following query:
with initData as(
select date('2016-08-16') stamp, 1 mark from sysibm.sysdummy1
union select date('2016-08-17') stamp, 1 mark from sysibm.sysdummy1
union select date('2017-01-03') stamp, 1 mark from sysibm.sysdummy1
union select date('2018-02-16') stamp, 1 mark from sysibm.sysdummy1
union select date('2018-02-17') stamp, 1 mark from sysibm.sysdummy1
)
select * from(
select
a.startDate, a.endDate, coalesce(sum(b.mark),0) as mark
from(
select startDate, endDate from(
select stamp startDate, stamp+1 YEAR endDate
from(
select stamp + ym YEAR stamp
from(
select date('2016-08-01') stamp from sysibm.sysdummy1
union
select stamp from initData
union
select stamp+1 DAY from initData
),
(
select 0 as ym from sysibm.sysdummy1
union select 1 as ym from sysibm.sysdummy1
union select 2 as ym from sysibm.sysdummy1
)
)
)
where endDate <= date('2019-08-01')
) a
left outer join(
select stamp, mark from initData
) b
on b.stamp >= a.startDate
and b.stamp < a.endDate
group by a.startDate, a.endDate
)
where mark < 3
order by startDate, endDate
This gives me my list of ranges that I'm looking which have less than 3 marks. Now I need to find full years that don't over lap with other dates.
2016-08-17 2017-08-17 2
2016-08-18 2017-08-18 1
2017-01-03 2018-01-03 1
2017-01-04 2018-01-04 0
2017-08-01 2018-08-01 2
2017-08-16 2018-08-16 2
2017-08-17 2018-08-17 2
2017-08-18 2018-08-18 2
2018-01-03 2019-01-03 2
2018-01-04 2019-01-04 2
2018-02-16 2019-02-16 2
2018-02-17 2019-02-17 1
2018-02-18 2019-02-18 0
2018-08-01 2019-08-01 0
I have finally came up with some solution, but it seems a bit slow and seems like there should be a better way to do it:
with initData as(
select date('2016-08-16') stamp, 1 mark from sysibm.sysdummy1
union select date('2016-08-17') stamp, 1 mark from sysibm.sysdummy1
union select date('2017-01-03') stamp, 1 mark from sysibm.sysdummy1
union select date('2018-02-16') stamp, 1 mark from sysibm.sysdummy1
union select date('2018-02-17') stamp, 1 mark from sysibm.sysdummy1
), dateRanges as(
select startDate, endDate, mark, row_number() over (order by startDate, endDate) rn from(
select
a.startDate, a.endDate, coalesce(sum(b.mark),0) as mark
from(
select startDate, endDate from(
select stamp startDate, stamp+1 YEAR endDate
from(
select stamp + ym YEAR stamp
from(
select date('2016-08-01') stamp from sysibm.sysdummy1
union
select stamp from initData
union
select stamp+1 DAY from initData
),
(
select 0 as ym from sysibm.sysdummy1
union select 1 as ym from sysibm.sysdummy1
union select 2 as ym from sysibm.sysdummy1
)
)
)
where endDate <= date('2019-08-01')
) a
left outer join(
select stamp, mark from initData
) b
on b.stamp >= a.startDate
and b.stamp < a.endDate
group by a.startDate, a.endDate
)
where mark < 3
), dateRangeLimit1 as(
select
a.startDate, a.endDate, a.mark, row_number() over (order by a.startDate, a.endDate) rn
from dateRanges a
left outer join dateRanges b
on a.startDate < b.endDate
and b.rn = 1
and a.rn != b.rn
where b.rn is null
)
select a.* from dateRangeLimit1 a
left outer join dateRangeLimit1 b
on a.startDate < b.endDate
and b.rn = 2 and a.rn <> b.rn and a.rn != 1
where b.rn is null
This gives me back my expected date ranges that don't over lap with each other:
2016-08-17 2017-08-17 2 1
2017-08-17 2018-08-17 2 2
I hope this makes a bit more sense.
I'm not sure your data is quite right, but nonetheless does this help?
WITH D(F,T) AS (VALUES
('2016-08-09','2017-08-09')
,('2016-08-16','2017-08-16')
,('2016-08-17','2017-08-17')
,('2016-08-18','2017-08-18')
,('2017-08-09','2018-08-09')
,('2017-08-16','2018-08-16')
,('2017-08-17','2018-08-17')
,('2017-08-18','2018-08-18')
,('2018-02-16','2019-02-16')
,('2018-02-17','2019-02-17')
,('2018-02-18','2019-02-18')
,('2018-08-09','2019-08-09')
)
SELECT F,T FROM
(
SELECT F,T
, LEAD(F,1) OVER(ORDER BY F ASC) AS NEXT_F
, LAG( T,1) OVER(ORDER BY F ASC) AS PREV_T
FROM D
)
WHERE T >= NEXT_F
OR F <= PREV_T
from dual apparently points to ORACLE.
Find the longest path of non-overlapping (end = start considered non-overlapping) intervals
select level, sys_connect_by_path (startDate || ' .. ' || endDate, '/') path
from blah a
connect by (prior startDate < startDate) and not(prior startDate < endDate and startDate < prior endDate)
order by level desc
-- fetch is 12c+ feature
fetch next 1 rows only;
Using sample data returns
3 /09-AUG-16 .. 09-AUG-17/09-AUG-17 .. 09-AUG-18/09-AUG-18 .. 09-AUG-19
Fiddle

I need data for all 24 months of data even with missing months

I need data for all 24 months of data even with missing months.
sample data
id custname reportdate sales
1 xx 31-JAN-17 1256
1 xx 31-MAR-17 3456
1 xx 30-JUN-17 5678
1 xx 31-DEC-17 6785
2 xx 31-JAN-17 1223
2 xx 31-APR-17 3435
2 xx 30-JUN-17 6777
2 xx 31-DEC-17 9643
what i need as a output
id custname reportdate sales
1 xx JAN-17 1256
1 xx FEB-17 <null>
1 xx MAR-17 3456
.....................................
.....................................
1 xx DEC-17 6785
And similarly for id 2 ....
Tried something like this without any luck
select CUSTNAME, reportdate, sales from
(
select TRIM( LEADING '0' FROM TO_CHAR( statementdate, 'YYYY-MM') ) AS REPORTDATE mm, CUSTNAME
froM MYTABLE) SALES,
(
select to_char(date '2017-01-01' + numtoyminterval(level,'month'), 'mm') MonthName
--i actually need format as MON-Last 2 digit of year eg:JAN-17
from dual
connect by level <= 24) ALLMONTHS
where mm = MonthName(+)
also tried with CTE and i cant use my_year.year_month CTE with outer join
my_year as (
select date '2017-01-31' start_date,date '2018-12-31' end_date from dual
)
select (to_char(add_months(trunc(start_date,'mm'),level - 1),'yyyy')||'-'||(to_char(add_months(trunc(start_date,'mm'),level - 1),'mm'))) year_month
from my_year
connect by trunc(end_date,'mm') >= add_months(trunc(start_date,'mm'),level - 1);
select id, customername, reportdate, sales,
TRIM( LEADING '0' FROM TO_CHAR( reportdate, 'YYYY-MM') ) AS stmntdate
from my_oracle_tbl a
where a.stmntdate = my_year.year_month (+)
also tried this as recommended by #Littlefoot, which isnt working
WITH mydates AS (
select LAST_DAY(add_months(date '2017-01-01', level - 1)) as mth, min_id,min_custname
from (
select min(id) as min_id, min(CUSTNAME) as min_custname
from my_oracle_tbl
)
connect by level <= 24)
select
nvl(t.id, a.min_id)id,
nvl(t.CUSTNAME,a.min_custname)CUSTNAME, a.mth, t.sales
from mydates a left join my_oracle_tbl t on a.mth= LAST_DAY(t.reporttdate)
where
t.id=2
;
You can use some old school tricks (UNION ALL IN COMBINATION WITH ADD_MONTHS FUNCTION AND SUM):
select id, custname,month,
decode(sum(sales),0,null,sum(sales)) sales from
(select id, custname, to_char(reportdate, 'mon-rrrr')
month,sales from my_oracle_tbl
UNION ALL
select a.*,b.*,0 sales from
(select distinct id, custname from my_oracle_tbl) a,
(
select to_char(sysdate,'mon')||'-2017' month from dual
UNION ALL
select ,to_char(add_months(sysdate,1),'mon')||'-2017' month from dual
UNION ALL
select ,to_char(add_months(sysdate,2),'mon')||'-2017' from dual
.......
UNION ALL
select ,to_char(add_months(sysdate,11),'mon')||'-2017' from dual) b
)
group by id, custname,month;
This is what i came up with do u see any concerns? is there a better way to write this? I need to get order by lowest to largest dates?? how can i achieve this. As of now it repeats order like this 12-2018,12-2017,11-2018,11-2017. I want 2017 dates first and then 2018
select CUSTNAME, reportdate, sum(sales), mth
from ( select to_char(add_months(date '2017-01-01', level - 1), 'mmyyyy') mth
from dual
connect by level <= 24)mo
left outer join oracle_tbl dc on mo.mth = to_char(reportdate, 'mmyyyy')
group by CUSTNAME, reportdate,mth
order by mth
Here's an example; see if it helps. It displays 12 months (you'd substitute it with 24 in line #21).
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> with test (id, custname, reportdate, sales) as
2 (select 1, 'xx', date '2017-01-31', 1256 from dual union all
3 select 1, 'xx', date '2017-03-31', 3456 from dual union all
4 select 1, 'xx', date '2017-06-30', 5678 from dual union all
5 --
6 select 2, 'xx', date '2017-03-31', 1223 from dual union all
7 select 2, 'xx', date '2017-07-31', 3435 from dual union all
8 select 2, 'xx', date '2017-09-30', 6777 from dual
9 ),
10 all_dates as
11 (select add_months(min_repdate, column_value - 1) c_mon,
12 min_id,
13 min_custname
14 from (select min(reportdate) min_repdate,
15 id min_id,
16 min(custname) min_custname
17 from test
18 group by id
19 ),
20 table(cast(multiset(select level from dual
21 connect by level <= 12
22 ) as sys.odcinumberlist))
23 )
24 select nvl(t.id, a.min_id) id,
25 nvl(t.custname, a.min_custname) custname,
26 a.c_mon,
27 t.sales
28 from all_dates a left join test t on a.min_id = t.id and a.c_mon = t.reportdate
29 order by id, a.c_mon;
ID CU C_MON SALES
---------- -- ---------- ----------
1 xx 31.01.2017 1256
1 xx 28.02.2017
1 xx 31.03.2017 3456
1 xx 30.04.2017
1 xx 31.05.2017
1 xx 30.06.2017 5678
1 xx 31.07.2017
1 xx 31.08.2017
1 xx 30.09.2017
1 xx 31.10.2017
1 xx 30.11.2017
1 xx 31.12.2017
2 xx 31.03.2017 1223
2 xx 30.04.2017
2 xx 31.05.2017
2 xx 30.06.2017
2 xx 31.07.2017 3435
2 xx 31.08.2017
2 xx 30.09.2017 6777
2 xx 31.10.2017
2 xx 30.11.2017
2 xx 31.12.2017
2 xx 31.01.2018
2 xx 28.02.2018
24 rows selected.
SQL>

How to get data for previous 7 days based on set of dates in groups in sql

I was going through this forum for my query to get data for previous 7 days,but most of them give it for current date.Below is my requirement:
I have a Table 1 as below:
These are start dates of week which is monday
from_date
2016-01-04
2016-01-11
2016-01-18
Table 2
I have all days of week here starting from monday.Ex: jan 04 - monday to jan 10 - sunday and so on for other weeks also.
get_date flag value
2016-01-04 N 4
2016-01-05 N 9
2016-01-06 Y 2
2016-01-07 Y 13
2016-01-08 Y 7
2016-01-09 Y 8
2016-01-10 Y 8
2016-01-11 Y 1
2016-01-12 Y 9
2016-01-13 N 8
2016-01-14 N 24
2016-01-15 N 8
2016-01-16 Y 4
2016-01-17 Y 5
2016-01-18 Y 9
2016-01-19 Y 2
2016-01-20 Y 8
2016-01-21 Y 4
2016-01-22 N 9
2016-01-23 N 87
2016-01-24 Y 3
Expected Result
here wk is the unique number for each start-end dates respectively
avg value is the avg of the values for the dates in that week.
last 2 days of the week are weekend days.
say 2016-01-09 and 2016-01-10 are weekends
from_date get_date Wk Total_days Total_weekdays_flag_Y Total_weekenddays_flag_Y Avg_value
2016-01-04 2016-01-10 1 7 3 2 6.714285714
2016-01-11 2016-01-17 2 7 2 2 8.428571429
2016-01-18 2016-01-24 3 7 4 1 17.42857143
Could anyone help me with this as I am not good at sql.
Thanks
select
from_date
, Wk
, count(case when day_of_week <=5 and flag = 'Y' then 1 end) as Total_weekdays_flag_Y
, count(case when day_of_week > 5 and flag = 'Y' then 1 end) as Total_weekenddays_flag_Y
, avg(value) as Avg_value
from (
select trunc(get_date,'IW') as from_date
, (trunc(get_date,'IW')- trunc(date'2016-01-04','IW'))/7 + 1 as Wk
, flag
, value
, get_date - trunc(get_date,'IW') as day_of_week
from Table_2)
group by from_date, Wk
order by from_date, Wk;
EDIT:
/*generate some test_data for table 2*/
with table_2 (get_date, flag, value) as (
select date'2016-01-03' + level,
DECODE(mod(level,3),0,'Y','N'),
round(dbms_random.value(0,10))
from dual connect by level < 101
),
/*generate some test_weeks for table 1*/
table_1 (FROM_date) as (select date'2016-01-04' + (level-1)*7 from dual connect by level < 101 )
/*main query */
select
from_date
, Wk
, count(day_of_week) as total
, count(case when day_of_week <=5 and flag = 'Y' then 1 end) as Total_weekdays_flag_Y
, count(case when day_of_week > 5 and flag = 'Y' then 1 end) as Total_weekenddays_flag_Y
, avg(value) as Avg_value
from (
select last_value(from_date ignore nulls) over (order by get_date) as from_date
,last_value(Wk ignore nulls) over (order by get_date) as Wk
, flag
, value
, get_date - trunc(get_date,'IW') as day_of_week
from Table_2 t2
full join (select row_number() over (order by from_date) as wk,from_date from table_1) t1 on t2.get_date = t1.from_date
)
group by from_date, Wk
having count(day_of_week) > 0
order by from_date, Wk
In the query below, I create the test data right within the query; in final form, you would delete the subqueries table_1 and table_2 and use the rest.
The syntax will work from Oracle 11.2 on. In Oracle 11.1, you need to move the column names in factored subqueries to the select... from dual part. Or, since you really only have one subquery (prep) and an outer query, you can write prep as an actual, in-line subquery.
Your arithmetic seems off on the average for the first week.
In your sample output you use get_date for the last day of the week. That is odd, since in table_2 that name has a different meaning. I used to_date in my output. I also do not show total_days - that is always 7, so why include it at all? (If it is not always 7, then there is something you didn't tell us; anyway, a count(...), if that is what it should be, is easy to add).
with
-- begin test data, can be removed in final solution
table_1 ( from_date ) as (
select date '2016-01-04' from dual union all
select date '2016-01-11' from dual union all
select date '2016-01-18' from dual
)
,
table_2 ( get_date, flag, value ) as (
select date '2016-01-04', 'N', 4 from dual union all
select date '2016-01-05', 'N', 9 from dual union all
select date '2016-01-06', 'Y', 2 from dual union all
select date '2016-01-07', 'Y', 13 from dual union all
select date '2016-01-08', 'Y', 7 from dual union all
select date '2016-01-09', 'Y', 8 from dual union all
select date '2016-01-10', 'Y', 8 from dual union all
select date '2016-01-11', 'Y', 1 from dual union all
select date '2016-01-12', 'Y', 9 from dual union all
select date '2016-01-13', 'N', 8 from dual union all
select date '2016-01-14', 'N', 24 from dual union all
select date '2016-01-15', 'N', 8 from dual union all
select date '2016-01-16', 'Y', 4 from dual union all
select date '2016-01-17', 'Y', 5 from dual union all
select date '2016-01-18', 'Y', 9 from dual union all
select date '2016-01-19', 'Y', 2 from dual union all
select date '2016-01-20', 'Y', 8 from dual union all
select date '2016-01-21', 'Y', 4 from dual union all
select date '2016-01-22', 'N', 9 from dual union all
select date '2016-01-23', 'N', 87 from dual union all
select date '2016-01-24', 'Y', 3 from dual
),
-- end test data, continue actual query
prep ( get_date, flag, value, from_date, wd_flag ) as (
select t2.get_date, t2.flag, t2.value, t1.from_date,
case when t2.get_date - t1.from_date <= 4 then 'wd' else 'we' end
from table_1 t1 inner join table_2 t2
on t2.get_date between t1.from_date and t1.from_date + 6
)
select from_date,
from_date + 6 as to_date,
row_number() over (order by from_date) as wk,
count(case when flag = 'Y' and wd_flag = 'wd' then 1 end)
as total_weekday_Y,
count(case when flag = 'Y' and wd_flag = 'we' then 1 end)
as total_weekend_Y,
round(avg(value), 6) as avg_value
from prep
group by from_date;
Output:
FROM_DATE TO_DATE WK TOTAL_WEEKDAY_Y TOTAL_WEEKEND_Y AVG_VALUE
---------- ---------- ---- --------------- --------------- ----------
2016-01-04 2016-01-10 1 3 2 7.285714
2016-01-11 2016-01-17 2 2 2 8.428571
2016-01-18 2016-01-24 3 4 1 17.428571

Querying the weeks for the whole month and displaying the content according to that month

I have a question regarding my analysis programming. I already have a query to show the weeks in a whole year. But im stuck when i need to sum up values regarding to each week's occurence. So this is my SQL code,
SELECT LEVEL WEEK_NUM_INCR,
TO_CHAR (start_date + (LEVEL - 1) * 7, 'WW') WEEK_POSITION /* WEEK POSITION FOR THE WHOLE YEAR */
,
TO_CHAR (start_date + (LEVEL - 1) * 7, 'DD-MM-YYYY') START_WEEK_DATE,
TO_CHAR (start_date + (LEVEL) * 7, 'DD-MM-YYYY') END_WEEK_DATE,
(SELECT SUM(ONSITE_UPD_QTY) FROM DTL_ERC_UPD#WELTES_SITEMON_LINK WHERE UPD_DATE BETWEEN
TO_CHAR (start_date + (LEVEL) * 7, 'MM/DD/YYYY') AND TO_CHAR (start_date + (LEVEL) * 7, 'MM/DD/YYYY') CONNECT BY start_date + (LEVEL - 1) * 7 < end_date)
FROM (SELECT TO_DATE ('01/01/2015', 'MM/DD/YYYY') start_date,
TO_DATE ('12/31/2015', 'MM/DD/YYYY') end_date
FROM DUAL)
CONNECT BY start_date + (LEVEL - 1) * 7 < end_date;
it would display the weeks but when i added this part in the middle which i have now,
(SELECT SUM(ONSITE_UPD_QTY) FROM DTL_ERC_UPD#WELTES_SITEMON_LINK WHERE UPD_DATE BETWEEN
TO_CHAR (start_date + (LEVEL) * 7, 'MM/DD/YYYY') AND TO_CHAR (start_date + (LEVEL) * 7, 'MM/DD/YYYY') CONNECT BY start_date + (LEVEL - 1) * 7 < end_date)
it throws these errors,
ORA-01843: not a valid month
ORA-02063: preceding line from WELTES_SITEMON_LINK
So for the DTL_ERC_UPD, I have
ONSITE_UPD_QTY UPD_DATE
1 2/5/2015 12:00:01 AM
1 2/5/2015 12:00:01 AM
1 2/4/2015
1 2/4/2015
1 2/4/2015
I am hoping that it would show 5 during feb 1st until 8th and zero on the rest of the row.
Please help me with this issue
below one is the sample table
select cast('01/08/2013' as Date) dte INTO #temp union all select
'03/01/2013' union all select
'11/01/2013' union all select
'12/01/2013' union all select
'10/21/2014' union all select
'10/27/2014' union all select
'10/30/2014' union all select
'10/31/2014' union all select
'11/01/2014' union all select
'11/02/2014' union all select
'11/04/2014' union all select
'11/05/2014' union all select
'11/08/2014' union all select
'11/09/2014' union all select
'11/11/2014' union all select
'11/20/2014' union all select
'11/07/2014' union all select
'07/11/2014' union all select
'11/13/2013' union all select
'09/01/2014' union all select
'11/03/2014' union all select
'11/18/2014' union all select
'12/05/2014' union all select
'07/24/2014' union all select
'07/26/2014' union all select
'07/27/2014' union all select
'07/28/2014' union all select
'07/29/2014' union all select
'07/30/2014' union all select
'01/01/2014' union all select
'02/01/2014' union all select
'04/01/2014' union all select
'05/01/2014' union all select
'06/01/2014' union all select
'06/01/2014' union all select
'07/01/2014' union all select
'07/01/2014' union all select
'11/05/2013' union all select
'06/16/2014' union all select
'06/17/2014' union all select
'06/18/2014' union all select
'06/19/2014' union all select
'06/20/2014' union all select
'06/21/2014' union all select
'06/22/2014' union all select
'06/23/2014' union all select
'06/24/2014' union all select
'06/25/2014' union all select
'06/26/2014' union all select
'06/27/2014' union all select
'06/28/2014' union all select
'06/29/2014'
now you can get week count start date of the week and end date of the week
select count([Week]) cont,[Week],
DATEADD(Day,(cast(SUBSTRING([Week],5,LEN( [Week])) as integer)*7)-7,
DATEADD(year,cast(SUBSTRING([Week],1,4) as integer)-1900,0)) startDte,
DATEADD(Day,cast(SUBSTRING([Week],5,LEN( [Week])) as integer)*7,
DATEADD(year,cast(SUBSTRING([Week],1,4) as integer)-1900,0)) endDte
from (select cast(datepart(YYYY,cast(dte as DATE)) as varchar(4))+''+cast(datepart(WW,cast(dte as DATE)) as varchar(2)) [Week],dte from #temp
) AS temp GROUP BY [Week]
ouput is
cont startDte endDte
1 2013-01-08 00:00:00.000 2013-01-15 00:00:00.000
1 2013-10-29 00:00:00.000 2013-11-05 00:00:00.000
1 2013-11-05 00:00:00.000 2013-11-12 00:00:00.000
1 2013-11-12 00:00:00.000 2013-11-19 00:00:00.000
1 2013-12-03 00:00:00.000 2013-12-10 00:00:00.000
1 2013-02-26 00:00:00.000 2013-03-05 00:00:00.000
1 2014-01-01 00:00:00.000 2014-01-08 00:00:00.000
1 2014-04-02 00:00:00.000 2014-04-09 00:00:00.000
1 2014-04-30 00:00:00.000 2014-05-07 00:00:00.000
2 2014-06-04 00:00:00.000 2014-06-11 00:00:00.000
6 2014-06-18 00:00:00.000 2014-06-25 00:00:00.000
7 2014-06-25 00:00:00.000 2014-07-02 00:00:00.000
3 2014-07-02 00:00:00.000 2014-07-09 00:00:00.000
1 2014-07-09 00:00:00.000 2014-07-16 00:00:00.000
2 2014-07-23 00:00:00.000 2014-07-30 00:00:00.000
4 2014-07-30 00:00:00.000 2014-08-06 00:00:00.000
1 2014-09-03 00:00:00.000 2014-09-10 00:00:00.000
1 2014-10-22 00:00:00.000 2014-10-29 00:00:00.000
4 2014-10-29 00:00:00.000 2014-11-05 00:00:00.000
6 2014-11-05 00:00:00.000 2014-11-12 00:00:00.000
2 2014-11-12 00:00:00.000 2014-11-19 00:00:00.000
2 2014-11-19 00:00:00.000 2014-11-26 00:00:00.000
1 2014-12-03 00:00:00.000 2014-12-10 00:00:00.000
1 2014-01-29 00:00:00.000 2014-02-05 00:00:00.000
Second connect by in your code is needless. Organize query in logical sections using proper join. Do not use date to char conversion for comparison, as already mentioned. Below is sample query that you can use:
with period as (
select to_date('02/01/2015', 'MM/DD/YYYY') start_date,
to_date('03/01/2015', 'MM/DD/YYYY') end_date from dual),
weeks as (
select level week_num_inc,
to_char(start_date + (level - 1) * 7, 'WW') week_position,
start_date + (level - 1) * 7 start_week_date,
start_date + level * 7 end_week_date
from period
connect by start_date + (level - 1) * 7 < end_date)
select week_num_inc, week_position, start_week_date, end_week_date,
nvl(sum(dtl_erc_upd.onsite_upd_qty), 0) quantity
from weeks w
left join dtl_erc_upd on start_week_date <= upd_date
and upd_date < end_week_date
group by week_num_inc, week_position, start_week_date, end_week_date
order by start_week_date
result:
WEEK_NUM_INC WEEK_POSITION START_WEEK_DATE END_WEEK_DATE QUANTITY
1 05 2015-02-01 2015-02-08 5
2 06 2015-02-08 2015-02-15 0
3 07 2015-02-15 2015-02-22 0
4 08 2015-02-22 2015-03-01 0