Find overlapping date range from a data set - sql

p_id book_num conf_num arrival_dt departure_dt create-dt room_num
353 21807 3328568 19-JUN-15 21-JUN-15 27-JUN-15 2408
353 21807 3328562 18-JUN-15 20-JUN-15 27-JUN-15 2408
In the above example arrival_dt and departure_dt is overlapping for 2 different
confirmation numbers for the same room number 2408
also I want to exclude the below set of records where arrival_dt and departure_dt are same
p_id book_num conf_num arrival_dt departure_dt create-dt room_num
353 21802 3328508 18-JUN-15 21-JUN-15 27-JUN-15 1909
353 21802 3328555 18-JUN-15 21-JUN-15 27-JUN-15 1909
Can you please help me with a SQL logic to find these kind of records in the table

SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE TEST ( p_id, book_num, conf_num, arrival_dt, departure_dt, create_dt, room_num ) AS
SELECT 353, 21807, 3328568, DATE '2015-06-19', DATE '2015-06-21', DATE '2015-06-27', 2408 FROM DUAL
UNION ALL SELECT 353, 21807, 3328562, DATE '2015-06-18', DATE '2015-06-20', DATE '2015-06-27', 2408 FROM DUAL
UNION ALL SELECT 353, 21802, 3328508, DATE '2015-06-18', DATE '2015-06-21', DATE '2015-06-27', 1909 FROM DUAL
UNION ALL SELECT 353, 21802, 3328555, DATE '2015-06-18', DATE '2015-06-21', DATE '2015-06-27', 1909 FROM DUAL
UNION ALL SELECT 353, 21801, 3328444, DATE '2015-06-17', DATE '2015-06-21', DATE '2015-06-27', 2000 FROM DUAL
UNION ALL SELECT 353, 21801, 3328445, DATE '2015-06-18', DATE '2015-06-20', DATE '2015-06-27', 2000 FROM DUAL
UNION ALL SELECT 353, 21803, 3328446, DATE '2015-06-19', DATE '2015-06-20', DATE '2015-06-27', 2001 FROM DUAL
UNION ALL SELECT 353, 21804, 3328447, DATE '2015-06-20', DATE '2015-06-21', DATE '2015-06-27', 2001 FROM DUAL;
Query 1:
SELECT *
FROM TEST t
WHERE EXISTS ( SELECT 'X'
FROM TEST x
WHERE x.room_num = t.room_num
AND x.arrival_dt < t.departure_dt
AND x.departure_dt > t.arrival_dt
AND NOT ( x.arrival_dt = t.arrival_dt
AND x.departure_dt = t.departure_dt ) )
Results:
| P_ID | BOOK_NUM | CONF_NUM | ARRIVAL_DT | DEPARTURE_DT | CREATE_DT | ROOM_NUM |
|------|----------|----------|------------------------|------------------------|------------------------|----------|
| 353 | 21807 | 3328568 | June, 19 2015 00:00:00 | June, 21 2015 00:00:00 | June, 27 2015 00:00:00 | 2408 |
| 353 | 21807 | 3328562 | June, 18 2015 00:00:00 | June, 20 2015 00:00:00 | June, 27 2015 00:00:00 | 2408 |
| 353 | 21801 | 3328444 | June, 17 2015 00:00:00 | June, 21 2015 00:00:00 | June, 27 2015 00:00:00 | 2000 |
| 353 | 21801 | 3328445 | June, 18 2015 00:00:00 | June, 20 2015 00:00:00 | June, 27 2015 00:00:00 | 2000 |

The correct logic is that one departs after the other arrivesa and the first arrives before the other departs. You can do this with a self-join or a where clause.
If you just want the records:
select r.*
from records r
where exists (select 1
from records r2
where r2.pid = r.pid and
r2.arrival_dt >= r.departure_dt and
r2.departure_dt <= r.arrival_dt
);

SELECT tbl.*
FROM table tbl
JOIN table tbl1 ON tbl.p_id= tbl1.p_id
WHERE tbl.Arrival_dt <= tbl1.Departure_dt
AND tbl.Departure_dt >= tbl1.Arrival_dt

Related

How to dynamically add rows with values of last 12 months of data when particular period is missing within the particular last 12 month period?

This is the input Table:
ITEM
QTY
DATEPERIOD
A
2
1/1/2020 0:00
A
3
2/1/2020 0:00
A
4
3/1/2020 0:00
A
1
4/1/2020 0:00
A
2
5/1/2020 0:00
A
2
6/1/2020 0:00
A
2
8/1/2020 0:00
A
2
10/1/2020 0:00
A
2
12/1/2020 0:00
A
2
1/1/2021 0:00
A
3
2/1/2021 0:00
A
4
3/1/2021 0:00
A
2
5/1/2021 0:00
A
2
6/1/2021 0:00
A
2
8/1/2021 0:00
A
1
9/1/2021 0:00
A
2
10/1/2021 0:00
A
1
11/1/2021 0:00
A
1
12/1/2021 0:00
This input table does not have data of 2021-July, when I have to calculate the data of last 12 month for each rows, I will be able to get data of last 12 months from dec 2021 to Aug 2021.
But since the input table does not have data of 2021-July, using usual query
SUM(qty) OVER (
PARTITION BY item
ORDER BY dateperiod
RANGE BETWEEN INTERVAL '11' MONTH PRECEDING
AND INTERVAL '0' MONTH FOLLOWING
) AS total,
would generate last 12 month data for June 2021. But the expected output is even if the data is not available in July-2021, is it possible to dynamically generate a row as last 12 month data for July-2021 which should be from July 2021 to Aug 2020. The result of the qty is: 19
similarly, the input table is missing data for April 2021. Then the query generate a row as last 12 month data for April-2021 which should be from April 2021 to May 2020. The result of the qty is: 19
So the expected output will be in the form of
ITEM
DATEPERIOD
Output
A
1/1/2020
2
A
2/1/2020
5
A
3/1/2020
9
A
4/1/2020
10
A
5/1/2020
12
A
6/1/2020
14
A
7/1/2020
14
A
8/1/2020
16
A
9/1/2020
16
A
10/1/2020
18
A
11/1/2020
18
A
12/1/2020
20
A
1/1/2021
20
A
2/1/2021
20
A
3/1/2021
20
A
4/1/2021
19
A
5/1/2021
19
A
6/1/2021
19
A
7/1/2021
19
A
8/1/2021
19
A
9/1/2021
20
A
10/1/2021
20
A
11/1/2021
21
A
12/1/2021
20
Please let me know if this is possible
You can use a hierarchical query to generate a calendar and the use an OUTER JOIN to join it to your data (however, since you are doing it for each item then you probably want a PARTITIONed OUTER JOIN):
WITH calendar (month) AS (
SELECT ADD_MONTHS(min_dp, LEVEL - 1) AS month
FROM (
SELECT MIN(dateperiod) AS min_dp,
MAX(dateperiod) AS max_dp
FROM table_name
)
CONNECT BY ADD_MONTHS(min_dp, LEVEL - 1) <= max_dp
)
SELECT item,
c.month AS dateperiod,
COALESCE(t.qty, 0) AS qty,
SUM(t.qty) OVER (
PARTITION BY t.item
ORDER BY c.month
RANGE BETWEEN INTERVAL '11' MONTH PRECEDING
AND INTERVAL '0' MONTH FOLLOWING
) AS total
FROM calendar c
LEFT OUTER JOIN table_name t
PARTITION BY (t.item)
ON (c.month = t.dateperiod);
Which, for your sample data:
CREATE TABLE table_name (ITEM, QTY, DATEPERIOD) AS
SELECT 'A', 2, DATE '2020-01-01' FROM DUAL UNION ALL
SELECT 'A', 3, DATE '2020-02-01' FROM DUAL UNION ALL
SELECT 'A', 4, DATE '2020-03-01' FROM DUAL UNION ALL
SELECT 'A', 1, DATE '2020-04-01' FROM DUAL UNION ALL
SELECT 'A', 2, DATE '2020-05-01' FROM DUAL UNION ALL
SELECT 'A', 2, DATE '2020-06-01' FROM DUAL UNION ALL
SELECT 'A', 2, DATE '2020-08-01' FROM DUAL UNION ALL
SELECT 'A', 2, DATE '2020-10-01' FROM DUAL UNION ALL
SELECT 'A', 2, DATE '2020-12-01' FROM DUAL UNION ALL
SELECT 'A', 2, DATE '2021-01-01' FROM DUAL UNION ALL
SELECT 'A', 3, DATE '2021-02-01' FROM DUAL UNION ALL
SELECT 'A', 4, DATE '2021-03-01' FROM DUAL UNION ALL
SELECT 'A', 2, DATE '2021-05-01' FROM DUAL UNION ALL
SELECT 'A', 2, DATE '2021-06-01' FROM DUAL UNION ALL
SELECT 'A', 2, DATE '2021-08-01' FROM DUAL UNION ALL
SELECT 'A', 1, DATE '2021-09-01' FROM DUAL UNION ALL
SELECT 'A', 2, DATE '2021-10-01' FROM DUAL UNION ALL
SELECT 'A', 1, DATE '2021-11-01' FROM DUAL UNION ALL
SELECT 'A', 1, DATE '2021-12-01' FROM DUAL;
Outputs:
ITEM
DATEPERIOD
QTY
TOTAL
A
2020-01-01 00:00:00
2
2
A
2020-02-01 00:00:00
3
5
A
2020-03-01 00:00:00
4
9
A
2020-04-01 00:00:00
1
10
A
2020-05-01 00:00:00
2
12
A
2020-06-01 00:00:00
2
14
A
2020-07-01 00:00:00
0
14
A
2020-08-01 00:00:00
2
16
A
2020-09-01 00:00:00
0
16
A
2020-10-01 00:00:00
2
18
A
2020-11-01 00:00:00
0
18
A
2020-12-01 00:00:00
2
20
A
2021-01-01 00:00:00
2
20
A
2021-02-01 00:00:00
3
20
A
2021-03-01 00:00:00
4
20
A
2021-04-01 00:00:00
0
19
A
2021-05-01 00:00:00
2
19
A
2021-06-01 00:00:00
2
19
A
2021-07-01 00:00:00
0
19
A
2021-08-01 00:00:00
2
19
A
2021-09-01 00:00:00
1
20
A
2021-10-01 00:00:00
2
20
A
2021-11-01 00:00:00
1
21
A
2021-12-01 00:00:00
1
20
db<>fiddle here

Count records that existed in a year for each year it has been issued until its end date

I asked a question a couple weeks ago and I thought I asked the correct question, but I needed to modify it. I am posting a new question, however the previous post can be found here Thanks to #Serg for the quick reply to my previous question.
I've copied and pasted the question below. The modification to my question is, I assumed that the end date was sysdate, whereas I actually have an END_DATE column to work from. So, instead of count all files that were active each year until sysdate, I want to count all files there were active each year until END_DATE.
My previous question edited for my new question:
I have an Oracle table containing a number of active files. Each row is a file and has unique file #, issue date and end date
File #
ISSUE_DATE
END_DATE
1254
15-OCT-1997
11-NOV-2005
5245
22-MAY-2005
15-OCT-2008
7852
02-APR-2015
05-DEC-2023
9852
11-MAR-2021
22-OCT-2028
etc
I want to query a count of how many files were active each year between the year in which it was issued and the year of its end date. So, if it was issued in 2010, then I want to include that file in the count for each year since it was issued (2010, 2011, 2012, etc), up to its end date.
I'd like my end table to loo like:
Year
COUNT_OF_FILES
1997
20
1998
32
1999
55
2000
42
...
...
2019
130
2020
155
2021
151
2022
101
2023
98
2024
61
Just use simple generator:
Step 1: get all years for each record:
with
t(File#, ISSUE_DATE, END_DATE) as (
select 1254, to_date('15-OCT-1997','dd-mon-yyyy'),to_date('11-NOV-2005','dd-mon-yyyy') from dual union all
select 5245, to_date('22-MAY-2005','dd-mon-yyyy'),to_date('15-OCT-2008','dd-mon-yyyy') from dual union all
select 7852, to_date('02-APR-2015','dd-mon-yyyy'),to_date('05-DEC-2023','dd-mon-yyyy') from dual union all
select 9852, to_date('11-MAR-2021','dd-mon-yyyy'),to_date('22-OCT-2028','dd-mon-yyyy') from dual
)
select
t.*, yyyy
from t
cross apply(
select
extract(year from ISSUE_DATE)+level-1 as yyyy
from dual
connect by extract(year from ISSUE_DATE)+level-1<=extract(year from END_DATE)
) gen_years
this will return:
FILE# ISSUE_DATE END_DATE YYYY
---------- ------------------- ------------------- ----------
1254 1997-10-15 00:00:00 2005-11-11 00:00:00 1997
1254 1997-10-15 00:00:00 2005-11-11 00:00:00 1998
1254 1997-10-15 00:00:00 2005-11-11 00:00:00 1999
1254 1997-10-15 00:00:00 2005-11-11 00:00:00 2000
1254 1997-10-15 00:00:00 2005-11-11 00:00:00 2001
1254 1997-10-15 00:00:00 2005-11-11 00:00:00 2002
1254 1997-10-15 00:00:00 2005-11-11 00:00:00 2003
1254 1997-10-15 00:00:00 2005-11-11 00:00:00 2004
1254 1997-10-15 00:00:00 2005-11-11 00:00:00 2005
5245 2005-05-22 00:00:00 2008-10-15 00:00:00 2005
5245 2005-05-22 00:00:00 2008-10-15 00:00:00 2006
5245 2005-05-22 00:00:00 2008-10-15 00:00:00 2007
5245 2005-05-22 00:00:00 2008-10-15 00:00:00 2008
7852 2015-04-02 00:00:00 2023-12-05 00:00:00 2015
7852 2015-04-02 00:00:00 2023-12-05 00:00:00 2016
7852 2015-04-02 00:00:00 2023-12-05 00:00:00 2017
7852 2015-04-02 00:00:00 2023-12-05 00:00:00 2018
7852 2015-04-02 00:00:00 2023-12-05 00:00:00 2019
7852 2015-04-02 00:00:00 2023-12-05 00:00:00 2020
7852 2015-04-02 00:00:00 2023-12-05 00:00:00 2021
7852 2015-04-02 00:00:00 2023-12-05 00:00:00 2022
7852 2015-04-02 00:00:00 2023-12-05 00:00:00 2023
9852 2021-03-11 00:00:00 2028-10-22 00:00:00 2021
9852 2021-03-11 00:00:00 2028-10-22 00:00:00 2022
9852 2021-03-11 00:00:00 2028-10-22 00:00:00 2023
9852 2021-03-11 00:00:00 2028-10-22 00:00:00 2024
9852 2021-03-11 00:00:00 2028-10-22 00:00:00 2025
9852 2021-03-11 00:00:00 2028-10-22 00:00:00 2026
9852 2021-03-11 00:00:00 2028-10-22 00:00:00 2027
9852 2021-03-11 00:00:00 2028-10-22 00:00:00 2028
Then just aggregate them:
select
yyyy, count(*) cnt
from t
cross apply(
select
extract(year from ISSUE_DATE)+level-1 as yyyy
from dual
connect by extract(year from ISSUE_DATE)+level-1<=extract(year from END_DATE)
) gen_years
group by yyyy;
Full test case with test data:
with
t(File#, ISSUE_DATE, END_DATE) as (
select 1254, to_date('15-OCT-1997','dd-mon-yyyy'),to_date('11-NOV-2005','dd-mon-yyyy') from dual union all
select 5245, to_date('22-MAY-2005','dd-mon-yyyy'),to_date('15-OCT-2008','dd-mon-yyyy') from dual union all
select 7852, to_date('02-APR-2015','dd-mon-yyyy'),to_date('05-DEC-2023','dd-mon-yyyy') from dual union all
select 9852, to_date('11-MAR-2021','dd-mon-yyyy'),to_date('22-OCT-2028','dd-mon-yyyy') from dual
)
select
yyyy, count(*) cnt
from t
cross apply(
select
extract(year from ISSUE_DATE)+level-1 as yyyy
from dual
connect by extract(year from ISSUE_DATE)+level-1<=extract(year from END_DATE)
) gen_years
group by yyyy
order by yyyy;
Output:
YYYY CNT
---------- ----------
1997 1
1998 1
1999 1
2000 1
2001 1
2002 1
2003 1
2004 1
2005 2
2006 1
2007 1
2008 1
2015 1
2016 1
2017 1
2018 1
2019 1
2020 1
2021 2
2022 2
2023 2
2024 1
2025 1
2026 1
2027 1
2028 1

How to aggregate rows in the range of timestamp in vertica db (vsql)

Suppose I have a table with data like this:
ts | bandwidth_bytes
---------------------+-----------------
2021-08-27 22:00:00 | 3792
2021-08-27 21:45:00 | 1164
2021-08-27 21:30:00 | 7062
2021-08-27 21:15:00 | 3637
2021-08-27 21:00:00 | 2472
2021-08-27 20:45:00 | 1328
2021-08-27 20:30:00 | 1932
2021-08-27 20:15:00 | 1434
2021-08-27 20:00:00 | 1530
2021-08-27 19:45:00 | 1457
2021-08-27 19:30:00 | 1948
2021-08-27 19:15:00 | 1160
I need to output something like this:
ts | bandwidth_bytes
---------------------+-----------------
2021-08-27 22:00:00 | 15,655
2021-08-27 21:00:00 | 7166
2021-08-27 20:00:00 | 6095
I want to do sum bandwidth_bytes over 1 hour timestamp of data.
I want to do this in vsql specifically.
More columns are present but for simplification I have shown only these two.
You can use date_trunc():
select [date_trunc('hour', ts)][1] as ts_hh, sum(bandwidth_bytes)
from t
group by ts_hh;
Use Vertica's lovely function TIME_SLICE().
You can't only go by hour, you can also go by slices of 2 or 3 hours, which DATE_TRUNC() does not offer.
You seem to want all between 20:00:01 and 21:00:00 to belong to a time slice of 21:00:00. In both DATE_TRUNC() and TIME_SLICE(), however, it's 20:00:00 to 20:59:59 that belongs to the same time slice. So I subtracted one second before applying TIME_SLICE() .
WITH
-- your in data ...
indata(ts,bandwidth_bytes) AS (
SELECT TIMESTAMP '2021-08-27 22:00:00',3792
UNION ALL SELECT TIMESTAMP '2021-08-27 21:45:00',1164
UNION ALL SELECT TIMESTAMP '2021-08-27 21:30:00',7062
UNION ALL SELECT TIMESTAMP '2021-08-27 21:15:00',3637
UNION ALL SELECT TIMESTAMP '2021-08-27 21:00:00',2472
UNION ALL SELECT TIMESTAMP '2021-08-27 20:45:00',1328
UNION ALL SELECT TIMESTAMP '2021-08-27 20:30:00',1932
UNION ALL SELECT TIMESTAMP '2021-08-27 20:15:00',1434
UNION ALL SELECT TIMESTAMP '2021-08-27 20:00:00',1530
UNION ALL SELECT TIMESTAMP '2021-08-27 19:45:00',1457
UNION ALL SELECT TIMESTAMP '2021-08-27 19:30:00',1948
UNION ALL SELECT TIMESTAMP '2021-08-27 19:15:00',1160
)
SELECT
TIME_SLICE(ts - INTERVAL '1 SECOND' ,1,'HOUR','END') AS ts
, SUM(bandwidth_bytes) AS bandwidth_bytes
FROM indata
GROUP BY 1
ORDER BY 1 DESC;
ts | bandwidth_bytes
---------------------+-----------------
2021-08-27 22:00:00 | 15655
2021-08-27 21:00:00 | 7166
2021-08-27 20:00:00 | 6095

Get all dates for all date ranges in table using SQL Server

I have table dbo.WorkSchedules(Id, From, To) where I store date ranges for work schedules. I want to create a view that will have all dates for all rows of WorkSchedules. Thanks to this I have 1 view with all dates for all schedules.
On web I only found solutions for 1 row like 2 parameters start and end. My issue is different where I have multiple rows with start and end range.
Example:
WorkSchedules
Id | From | To
---+------------+-----------
1 | 2018-01-01 | 2018-01-05
2 | 2018-01-08 | 2018-01-12
Desired result
1 | 2018-01-01
2 | 2018-01-02
3 | 2018-01-03
4 | 2018-01-04
5 | 2018-01-05
6 | 2018-01-08
7 | 2018-01-09
8 | 2018-01-10
9 | 2018-01-11
10| 2018-01-12
If you are regularly dealing with "jobs" and "schedules" then I propose that you need a permanent calendar table (a table where each row is a unique date). You can create rows for dates dynamically but why do this many times when you can do it once and just re-use?
A calendar table, even of several decades, isn't "big" and when indexed they can be very fast as well. You can also store information about holidays and/or fiscal periods etc.
There are many scripts available to produce these tables, here's an answer with 2 scripts on this site: https://stackoverflow.com/a/5635628/2067753
Assuming you use the second (more comprehensive) script, then you can exclude weekends, or other conditions such as holidays, from query results.
Once you have a permanent Calendar table this style of query may be used:
CREATE TABLE WorkSchedules(
Id INTEGER NOT NULL PRIMARY KEY
,[From] DATE NOT NULL
,[To] DATE NOT NULL
);
INSERT INTO WorkSchedules(Id,[From],[To]) VALUES (1,'2018-01-01','2018-01-05');
INSERT INTO WorkSchedules(Id,[From],[To]) VALUES (2,'2018-01-12','2018-01-12');
with range as (
select min(ws.[From]) as dt_from, max(ws.[To]) dt_to
from WorkSchedules as ws
)
select c.*
from calendar as c
inner join range on c.date between range.dt_from and range.dt_to
where c.KindOfDay = 'BANKDAY'
order by c.date
and the result looks like this (note: "News Years Day" has been excluded)
Date Year Quarter Month Week Day DayOfYear Weekday Fiscal_Year Fiscal_Quarter Fiscal_Month KindOfDay Description
---- --------------------- ------ --------- ------- ------ ----- ----------- --------- ------------- ---------------- -------------- ----------- -------------
1 02.01.2018 00:00:00 2018 1 1 1 2 2 2 2018 1 1 BANKDAY NULL
2 03.01.2018 00:00:00 2018 1 1 1 3 3 3 2018 1 1 BANKDAY NULL
3 04.01.2018 00:00:00 2018 1 1 1 4 4 4 2018 1 1 BANKDAY NULL
4 05.01.2018 00:00:00 2018 1 1 1 5 5 5 2018 1 1 BANKDAY NULL
5 08.01.2018 00:00:00 2018 1 1 2 8 8 1 2018 1 1 BANKDAY NULL
6 09.01.2018 00:00:00 2018 1 1 2 9 9 2 2018 1 1 BANKDAY NULL
7 10.01.2018 00:00:00 2018 1 1 2 10 10 3 2018 1 1 BANKDAY NULL
8 11.01.2018 00:00:00 2018 1 1 2 11 11 4 2018 1 1 BANKDAY NULL
9 12.01.2018 00:00:00 2018 1 1 2 12 12 5 2018 1 1 BANKDAY NULL
Without the where clause the full range is:
Date Year Quarter Month Week Day DayOfYear Weekday Fiscal_Year Fiscal_Quarter Fiscal_Month KindOfDay Description
---- --------------------- ------ --------- ------- ------ ----- ----------- --------- ------------- ---------------- -------------- ----------- ----------------
1 01.01.2018 00:00:00 2018 1 1 1 1 1 1 2018 1 1 HOLIDAY New Year's Day
2 02.01.2018 00:00:00 2018 1 1 1 2 2 2 2018 1 1 BANKDAY NULL
3 03.01.2018 00:00:00 2018 1 1 1 3 3 3 2018 1 1 BANKDAY NULL
4 04.01.2018 00:00:00 2018 1 1 1 4 4 4 2018 1 1 BANKDAY NULL
5 05.01.2018 00:00:00 2018 1 1 1 5 5 5 2018 1 1 BANKDAY NULL
6 06.01.2018 00:00:00 2018 1 1 1 6 6 6 2018 1 1 SATURDAY NULL
7 07.01.2018 00:00:00 2018 1 1 1 7 7 7 2018 1 1 SUNDAY NULL
8 08.01.2018 00:00:00 2018 1 1 2 8 8 1 2018 1 1 BANKDAY NULL
9 09.01.2018 00:00:00 2018 1 1 2 9 9 2 2018 1 1 BANKDAY NULL
10 10.01.2018 00:00:00 2018 1 1 2 10 10 3 2018 1 1 BANKDAY NULL
11 11.01.2018 00:00:00 2018 1 1 2 11 11 4 2018 1 1 BANKDAY NULL
12 12.01.2018 00:00:00 2018 1 1 2 12 12 5 2018 1 1 BANKDAY NULL
and weekends and holidays may be excluded using the column KindOfDay
See this as a demonstration (with build of calendar table) here: http://rextester.com/CTSW63441
Ok, I worked this out for you, thinking you mean that you meant 01/08/2018 as a From date in the second row.
/*WorkSchedules
Id| From | To
1 | 2018-01-01 | 2018-01-05
2 | 2018-01-08 | 2018-01-12
*/
--DROP TABLE #WorkSchedules;
CREATE TABLE #WorkSchedules (
ID int,
[DateFrom] DATE,
[DateTo] DATE
)
INSERT INTO #WorkSchedules
SELECT 1, '2018-01-01', '2018-01-05'
UNION
SELECT 2, '2018-01-08', '2018-01-12'
;WITH CTEDATELIMITS AS (
SELECT [DateFrom], [DateTo]
FROM #WorkSchedules
)
,CTEDATES AS
(
SELECT [DateFrom] as [DateResult] FROM CTEDATELIMITS
UNION ALL
SELECT DATEADD(Day, 1, [DateResult]) FROM CTEDATES
JOIN CTEDATELIMITS ON CTEDATES.[DateResult] >= CTEDATELIMITS.[DateFrom]
AND CTEDATES.dateResult < CTEDATELIMITS.[DateTo]
)
SELECT [DateResult] FROM CTEDATES
ORDER BY [DateResult]
You would use a recursive CTE:
with dates as (
select from, to, from as date
from WorkSchedules
union all
select from, to, dateadd(day, 1, date)
from dates
where date < to
)
select row_number() over (order by date), date
from dates;
Note that from and to are reserved words in SQL. They are lousy names for identifiers. I have not escaped them because I assume they are not the actual names of the columns.

SQL Server : how to group values by month interval with offset

I have a query that groups aggregated sum values by month.
This is the query:
Declare #IsByStatus bit
Set #IsByStatus = 0
SELECT
CAST((DATEDIFF(month, '2012-01-01T06:00:00', datTimeStamp)) AS int) AS [Index] ,
Min(datTimeStamp) as [From],
Max(datTimeStamp) as [To],
Sum(CASE CAST(intIO_ID AS nvarchar(100))
WHEN N'284' THEN Value ELSE NULL END) AS [286]
FROM
[IOValuesFn](#IsByStatus) IOValues
WHERE
datTimeStamp >= '2012-01-01T06:00:00'
AND datTimeStamp < '2013-01-01T05:59:59'
AND intIO_ID IN (284)
GROUP BY
CAST ((DATEDIFF(Month,'2012-01-01T06:00:00', datTimeStamp)) AS int)
ORDER BY
[From]
And this is the result:
Index From To 286
0 2012-01-07 07:00:00.000 2012-01-31 23:00:00.000 142579.898864746
1 2012-02-01 00:00:00.000 2012-02-29 23:00:00.000 139486.498001099
2 2012-03-01 00:00:00.000 2012-03-31 23:00:00.000 99516.3022232056
3 2012-04-01 00:00:00.000 2012-04-30 23:00:00.000 84597.599899292
4 2012-05-01 00:00:00.000 2012-05-31 23:00:00.000 67085.2983112335
5 2012-06-01 00:00:00.000 2012-06-30 23:00:00.000 67768.9982643127
6 2012-07-01 00:00:00.000 2012-07-31 23:00:00.000 121100.264842987
7 2012-08-01 00:00:00.000 2012-08-31 23:00:00.000 165768.90776825
8 2012-09-01 00:00:00.000 2012-09-30 23:00:00.000 97441.7333068848
9 2012-10-01 00:00:00.000 2012-10-31 23:00:00.000 153764.736312866
10 2012-11-01 00:00:00.000 2012-11-30 23:00:00.000 153601.413961411
11 2012-12-01 00:00:00.000 2012-12-31 23:00:00.000 142521.07028389
12 2013-01-01 00:00:00.000 2013-01-01 05:00:00.000 1192.32000732422
Now I want to do the similar logic, that will also insert an offset in the month start-end time.
e.g. the first period will start on january 1'st on 11:00 AM and will end at february 1 10:59:59 AM.
Same goes for each subsequent month.
Thanks in advance for your help, Omer
Have a look at the example below. The trick is to add the negative amount of offset such that any hour prior to 11am on the first day of the month is "pushed" into the prior month.
Schema Setup:
create function iovaluesfn(#isbystatus bit) returns table as return
select datTimeStamp = '20130101 10:50', intIO_ID = 284, Value = 1 union all
select '20130101 11:00', 284, 1 union all
select '20130102 11:00', 284, 2 union all
select '20130301 11:00', 284, 3 union all
select '20130401 11:00', 284, 4 union all
select '20120501 11:00', 284, 5 union all
select '20120601 11:00', 284, 6 union all
select '20120101 11:00', 284, 7 union all
select '20120102 11:00', 284, 8 union all
select '20120101 11:01', 284, 9 union all
select '20120101 10:59', 284,10 union all -- ** this value is counted in Dec 2011
select '20120101 11:00', 284,11 union all
select '20120101 11:01', 281,12 union all
select '20120101 10:59', 281,13 union all
select '20120101 11:00', 281,14
GO
Query:
Declare #IsByStatus bit;
Set #IsByStatus = 0;
;with IOValues as (
select DATEADD(hour, -11, datTimeStamp) datTimeStamp, intIO_ID, Value
FROM [IOValuesFn](#IsByStatus)
WHERE datTimeStamp >= '2012-01-01T06:00:00' AND datTimeStamp < '2013-01-01T05:59:59'
AND intIO_ID IN (284)
)
SELECT CAST((DATEDIFF(month,'2012-01-01T06:00:00',datTimeStamp)) AS int) AS [Index],
Min(datTimeStamp) as [From],
Max(datTimeStamp) as [To],
Sum(CASE CAST(intIO_ID AS nvarchar(100))
WHEN N'284' THEN Value ELSE NULL END) AS [286]
FROM IOValues
GROUP BY CAST ((DATEDIFF(Month,'2012-01-01T06:00:00',datTimeStamp))AS int)
order by [From];
Results:
| INDEX | FROM | TO | 286 |
----------------------------------------------------------
| -1 | December, 31 2011 | December, 31 2011 | 10*** |
| 0 | January, 01 2012 | January, 02 2012 | 35 |
| 4 | May, 01 2012 | May, 01 2012 | 5 |
| 5 | June, 01 2012 | June, 01 2012 | 6 |
SQL Fiddle Demo