SQL consolidate consecutive date - sql

Hi could anyone help me with the SQL Query.
I want to display all the consecutive dates in the db where there is at least 2 consecutive dates.
Below are an example of the output what i was hoping for.
here is a list of dates:
2016-06-24 00:00:00.000
2016-06-24 00:00:00.000
2016-06-24 00:00:00.000
2016-06-25 00:00:00.000
2016-06-25 00:00:00.000
2016-06-26 00:00:00.000
2016-05-26 00:00:00.000
2016-05-25 00:00:00.000
2016-04-04 00:00:00.000
2016-06-26 00:00:00.000
----------output----------
| Start Date | End Date | Count | consecutive Date |
| 2016-05-25 00:00:00.000 | 2016-05-25 00:00:00.000 | 1 | 2 |
| 2016-05-25 00:00:00.000 | 2016-05-26 00:00:00.000 | 1 | 2 |
| 2016-06-24 00:00:00.000 | 2016-06-25 00:00:00.000 | 2 | 2 |
| 2016-06-24 00:00:00.000 | 2016-06-26 00:00:00.000 | 2 | 3 |
| 2016-06-25 00:00:00.000 | 2016-06-26 00:00:00.000 | 2 | 2 |
This is what I have currently:
WITH t AS (
SELECT SWITCHOFFSET(CONVERT(DATETIMEOFFSET, dateAvailable), '+08:00') d,
ROW_NUMBER() OVER(ORDER BY dateAvailable) i
FROM user_dateTbl
GROUP BY dateAvailable
)
SELECT MIN(d),MAX(d)
FROM t
GROUP BY DATEDIFF(day,i,d)
please help me out thank you. If your unsure of what I am writing do feel free to write in the comment below.

Related

How to calcute future datetime after few workinghours

I am trying to calculate what date will be after 2 or more working hours from now even if I'll start calculating on weekend or after workhours it should be like:
working hours are from 8am to 4pm
I start calculating at Friday at 3pm so if I'll start calculating result should be Monday 9am
if(#data_przyj>#WorkStart AND DATEPART(DATEADD(MINUTE,#ileNaZapytanie,#data_przyj)<#WorkFinish)
BEGIN
while (DATEPART(dw, #CurrentDate)!=1 AND DATEPART(dw, #CurrentDate)!=7))
BEGIN
SET #CurrentDate = DATEADD(day, 1, #CurrentDate)
SET #czyBylPrzeskok =1
END
if (#czyBylPrzeskok =1)
BEGIN
SET #LastDay = #CurrentDate
SET #LastDay = DATEADD(MINUTE, datediff(MINUTE,DATEADD(dd, 0, DATEDIFF(MINUTE, 0, #data_przyj)),#WorkStart), #LastDay)
SET #LastDay = DATEADD(HOUR, datediff(MINUTE,DATEADD(dd, 0, DATEDIFF(HOUR, 0, #data_przyj)),#WorkStart), #LastDay)
END
ELSE
BEGIN
SET #LastDay = DATEADD(MINUTE,#ileNaZapytanie,#data_przyj)
END
SET #IsCalculated = 1
END
else if(#data_przyj>#WorkStart AND DATEADD(MINUTE,#ileNaZapytanie,#data_przyj)>#WorkFinish)
BEGIN
SET #LastDay =DateADD(DD,3,GETDATE());
SET #IsCalculated = 1
END
else if(#data_przyj<#WorkStart )
BEGIN
SET #LastDay =GETDATE();
SET #IsCalculated = 1
END
END
EDIT:
for example working hours:8:00 - 16:00 i have Date '2019-09-06 15:00' so after adding 2 working hours should be '2019-09-09 09:00', for date '2019-09-06 13:00' should be '2019-09-06 15:00' etc
The following solution uses a calendar table with working hours, then use a rolling sum to accumulate each day's business hours and find which day you need to end with.
Using a calendar table will give you the flexibility of having different business time periods and very easily adding or removing holidays.
Setup (calendar table):
IF OBJECT_ID('tempdb..#WorkingCalendar') IS NOT NULL
DROP TABLE #WorkingCalendar
CREATE TABLE #WorkingCalendar (
Date DATE PRIMARY KEY,
IsWorkingDay BIT,
WorkingStartTime DATETIME,
WorkingEndTime DATETIME)
SET DATEFIRST 1 -- 1: Monday, 7: Sunday
DECLARE #StartDate DATE = '2019-01-01'
DECLARE #EndDate DATE = '2030-01-01'
;WITH RecursiveDates AS
(
SELECT
GeneratedDate = #StartDate
UNION ALL
SELECT
GeneratedDate = DATEADD(DAY, 1, R.GeneratedDate)
FROM
RecursiveDates AS R
WHERE
R.GeneratedDate < #EndDate
)
INSERT INTO #WorkingCalendar (
Date,
IsWorkingDay,
WorkingStartTime,
WorkingEndTime)
SELECT
Date = R.GeneratedDate,
IsWorkingDay = CASE
WHEN DATEPART(WEEKDAY, R.GeneratedDate) BETWEEN 1 AND 5 THEN 1 -- From Monday to Friday
ELSE 0 END,
WorkingStartTime = CASE
WHEN DATEPART(WEEKDAY, R.GeneratedDate) BETWEEN 1 AND 5
THEN CONVERT(DATETIME, R.GeneratedDate) + CONVERT(DATETIME, '08:00:00') END,
WorkingEndTime = CASE
WHEN DATEPART(WEEKDAY, R.GeneratedDate) BETWEEN 1 AND 5
THEN CONVERT(DATETIME, R.GeneratedDate) + CONVERT(DATETIME, '16:00:00') END
FROM
RecursiveDates AS R
OPTION
(MAXRECURSION 0)
Generates a table like the following:
+------------+--------------+-------------------------+-------------------------+
| Date | IsWorkingDay | WorkingStartTime | WorkingEndTime |
+------------+--------------+-------------------------+-------------------------+
| 2019-01-01 | 1 | 2019-01-01 08:00:00.000 | 2019-01-01 16:00:00.000 |
| 2019-01-02 | 1 | 2019-01-02 08:00:00.000 | 2019-01-02 16:00:00.000 |
| 2019-01-03 | 1 | 2019-01-03 08:00:00.000 | 2019-01-03 16:00:00.000 |
| 2019-01-04 | 1 | 2019-01-04 08:00:00.000 | 2019-01-04 16:00:00.000 |
| 2019-01-05 | 0 | NULL | NULL |
| 2019-01-06 | 0 | NULL | NULL |
| 2019-01-07 | 1 | 2019-01-07 08:00:00.000 | 2019-01-07 16:00:00.000 |
| 2019-01-08 | 1 | 2019-01-08 08:00:00.000 | 2019-01-08 16:00:00.000 |
| 2019-01-09 | 1 | 2019-01-09 08:00:00.000 | 2019-01-09 16:00:00.000 |
| 2019-01-10 | 1 | 2019-01-10 08:00:00.000 | 2019-01-10 16:00:00.000 |
| 2019-01-11 | 1 | 2019-01-11 08:00:00.000 | 2019-01-11 16:00:00.000 |
| 2019-01-12 | 0 | NULL | NULL |
| 2019-01-13 | 0 | NULL | NULL |
| 2019-01-14 | 1 | 2019-01-14 08:00:00.000 | 2019-01-14 16:00:00.000 |
| 2019-01-15 | 1 | 2019-01-15 08:00:00.000 | 2019-01-15 16:00:00.000 |
| 2019-01-16 | 1 | 2019-01-16 08:00:00.000 | 2019-01-16 16:00:00.000 |
| 2019-01-17 | 1 | 2019-01-17 08:00:00.000 | 2019-01-17 16:00:00.000 |
+------------+--------------+-------------------------+-------------------------+
Proposed Solution:
DECLARE #v_BusinessHoursToAdd INT = 2
DECLARE #v_CurrentDateTimeHour DATETIME = '2019-09-06 15:00'
;WITH CalendarFromNow AS
(
SELECT
T.Date,
WorkingStartTime = CASE
WHEN #v_CurrentDateTimeHour BETWEEN T.WorkingStartTime AND T.WorkingEndTime THEN #v_CurrentDateTimeHour
ELSE T.WorkingStartTime END,
WorkingEndTime = T.WorkingEndTime
FROM
#WorkingCalendar AS T
WHERE
T.Date >= CONVERT(DATE, #v_CurrentDateTimeHour) AND
T.IsWorkingDay = 1
),
RollingBusinessSum AS
(
SELECT
C.Date,
C.WorkingStartTime,
C.WorkingEndTime,
AmountBusinessHours = DATEDIFF(HOUR, C.WorkingStartTime, C.WorkingEndTime),
RollingBusinessHoursSum = SUM(DATEDIFF(HOUR, C.WorkingStartTime, C.WorkingEndTime)) OVER (ORDER BY C.Date),
PendingHours = #v_BusinessHoursToAdd - SUM(DATEDIFF(HOUR, C.WorkingStartTime, C.WorkingEndTime)) OVER (ORDER BY C.Date)
FROM
CalendarFromNow AS C
)
SELECT TOP 1
EndingHour = DATEADD(
HOUR,
R.PendingHours,
R.WorkingEndTime)
FROM
RollingBusinessSum AS R
WHERE
R.PendingHours < 0
ORDER BY
R.Date
Explanation:
The first CTE CalendarFromNow is simply filtering the calendar dates from the current hour's date and reducing the starting working datetime to the current hour, since this is gonna be the starting point to count hours from.
+------------+-------------------------+-------------------------+
| Date | WorkingStartTime | WorkingEndTime |
+------------+-------------------------+-------------------------+
| 2019-09-06 | 2019-09-06 15:00:00.000 | 2019-09-06 16:00:00.000 |
| 2019-09-09 | 2019-09-09 08:00:00.000 | 2019-09-09 16:00:00.000 |
| 2019-09-10 | 2019-09-10 08:00:00.000 | 2019-09-10 16:00:00.000 |
| 2019-09-11 | 2019-09-11 08:00:00.000 | 2019-09-11 16:00:00.000 |
| 2019-09-12 | 2019-09-12 08:00:00.000 | 2019-09-12 16:00:00.000 |
| 2019-09-13 | 2019-09-13 08:00:00.000 | 2019-09-13 16:00:00.000 |
| 2019-09-16 | 2019-09-16 08:00:00.000 | 2019-09-16 16:00:00.000 |
+------------+-------------------------+-------------------------+
The second CTE RollingBusinessSum is calculating the amount of business hours on each day and accumulating them over the days. The last column PendingHours is the result of the amount of hours we need to add from now subtracted by the sum of business hours over the days.
+------------+-------------------------+-------------------------+---------------------+-------------------------+--------------+
| Date | WorkingStartTime | WorkingEndTime | AmountBusinessHours | RollingBusinessHoursSum | PendingHours |
+------------+-------------------------+-------------------------+---------------------+-------------------------+--------------+
| 2019-09-06 | 2019-09-06 15:00:00.000 | 2019-09-06 16:00:00.000 | 1 | 1 | 1 |
| 2019-09-09 | 2019-09-09 08:00:00.000 | 2019-09-09 16:00:00.000 | 8 | 9 | -7 |
| 2019-09-10 | 2019-09-10 08:00:00.000 | 2019-09-10 16:00:00.000 | 8 | 17 | -15 |
| 2019-09-11 | 2019-09-11 08:00:00.000 | 2019-09-11 16:00:00.000 | 8 | 25 | -23 |
| 2019-09-12 | 2019-09-12 08:00:00.000 | 2019-09-12 16:00:00.000 | 8 | 33 | -31 |
| 2019-09-13 | 2019-09-13 08:00:00.000 | 2019-09-13 16:00:00.000 | 8 | 41 | -39 |
+------------+-------------------------+-------------------------+---------------------+-------------------------+--------------+
Finally the first day that the PendingHours column is negative is the day that we arrived at the amount of hours we wanted to add. This is the TOP 1 with ORDER BY. To get the final datetime, we just subtract the pending hours to the end time for that particular day.
+------------+-------------------------+-------------------------+---------------------+-------------------------+--------------+-------------------------+
| Date | WorkingStartTime | WorkingEndTime | AmountBusinessHours | RollingBusinessHoursSum | PendingHours | EndingHour |
+------------+-------------------------+-------------------------+---------------------+-------------------------+--------------+-------------------------+
| 2019-09-09 | 2019-09-09 08:00:00.000 | 2019-09-09 16:00:00.000 | 8 | 9 | -7 | 2019-09-09 09:00:00.000 |
+------------+-------------------------+-------------------------+---------------------+-------------------------+--------------+-------------------------+
You might have to tweak performance and do boundary tests but this might give you a flexible idea of how to work with working hours at holidays or different time periods.

How to get the 1st of September from the previous September?

If I want to select a date relative to today's date I can do something like:
DateAdd(month, -2, N'1-Jan-2019')
This will give me the 1st of November 2018.
How would I get the Date of the 1st of September, from the previous year?
E.G
Say it's July 2019,
I want the 1st of September 2018, NOT 2019.
However,
Say it's November 2019,
I want the 1st of September 2019, NOT 2018.
How is this possible?
You can do this by subtracting 8 months from your date value and then using the resulting year to build up your September date:
declare #d table(d date);
insert into #d values ('20170101'),('20180101'),('20181101'),('20190101'),('20191001'),('20190901'),('20190921'),('20190808');
select d
,datefromparts(year(dateadd(month,-8,d)),9,1) as PrevSeptDate
,datetimefromparts(year(dateadd(month,-8,d)),9,1,0,0,0,0) as PrevSeptDateTime
from #d
order by d;
Output
+------------+--------------+-------------------------+
| d | PrevSeptDate | PrevSeptDateTime |
+------------+--------------+-------------------------+
| 2017-01-01 | 2016-09-01 | 2016-09-01 00:00:00.000 |
| 2018-01-01 | 2017-09-01 | 2017-09-01 00:00:00.000 |
| 2018-11-01 | 2018-09-01 | 2018-09-01 00:00:00.000 |
| 2019-01-01 | 2018-09-01 | 2018-09-01 00:00:00.000 |
| 2019-08-08 | 2018-09-01 | 2018-09-01 00:00:00.000 |
| 2019-09-01 | 2019-09-01 | 2019-09-01 00:00:00.000 |
| 2019-09-21 | 2019-09-01 | 2019-09-01 00:00:00.000 |
| 2019-10-01 | 2019-09-01 | 2019-09-01 00:00:00.000 |
+------------+--------------+-------------------------+

Postgres, Update TIMESTAMP to current date but preserve time of day

In my Postgres database, I have the following table:
SELECT start_at, end_at FROM schedules;
+---------------------+---------------------+
| start_at | end_at |
|---------------------+---------------------|
| 2016-09-05 16:30:00 | 2016-09-05 17:30:00 |
| 2016-09-05 17:30:00 | 2016-09-05 18:30:00 |
| 2017-08-13 03:00:00 | 2017-08-13 07:00:00 |
| 2017-08-13 03:00:00 | 2017-08-13 07:00:00 |
| 2017-08-13 18:42:26 | 2017-08-13 21:30:46 |
| 2017-08-10 00:00:00 | 2017-08-10 03:30:00 |
| 2017-08-09 18:00:00 | 2017-08-10 03:00:00 |
| 2017-08-06 23:00:00 | 2017-08-07 03:00:00 |
| 2017-08-07 01:00:00 | 2017-08-07 03:48:20 |
| 2017-08-07 01:00:00 | 2017-08-07 03:48:20 |
| 2017-08-07 18:05:00 | 2017-08-07 20:53:20 |
| 2017-08-07 14:00:00 | 2017-08-08 01:00:00 |
| 2017-08-07 18:00:00 | 2017-08-07 20:48:20 |
| 2017-08-08 08:00:00 | 2017-08-09 00:00:00 |
| 2017-08-09 21:30:00 | 2017-08-10 00:18:20 |
| 2017-08-13 03:53:26 | 2017-08-13 06:41:46 |
+---------------------+---------------------+
Assume I also have an ID column, what I want to do is update all the start and end times to be for today (now), what is the most efficient SQL to accomplish this? My table could have millions of rows.
the best I can think of is this:
update schedules
set start_at = current_date + start_at::time
, end_at = current_date + end_at::time
WHERE start_at::date <> current_date
or end_at::date <> current_date;
The arithmetic is fast compared to accessing the rows.
if not all rows need updating, the where clause will help efficiency. Updates are expensive.

Limitation of SQL Server recursive query

I have this data structure
PresentationSession: 1 day has 2 sessions: morning=1, afternoon=2. Some presentation is the whole day presentation, some only has morning or afternoon.
dayofweek column represents the day of the week for the presentation-eg Monday=2, Tues=3...
Maximum session is the maximum of consecutive sessions a presentation last. Presentation has to be confined within a multiple of a week. For example, if the presentation take place in Wed, Th, Fr and the max Session is 12 then the presentation last 2 weeks. (1 day has 2 sessions). However, if there is a holiday in says Thu, then it is still 2 weeks but 10 sessions, hence the MaxSession is still 12. On the other side of the spectrum, if the MaxSession is only 2, then there will be 3 different presentation on that week.
Newblock marks the start of the week, 0= new start of the week.
rn is the sequential number of the day
My goal is to aggregate the records and consolidate the information to a more human readable format with fromDate, endDate, presentationId, Name (see illustration)
The following recursive cte script does the job just fine but it only works with a data set of 50 records. It will error out with a data set of 2000+ records.
The error is:
Msg 530, Level 16, State 1, Line 110
The statement terminated. The maximum recursion 100 has been exhausted before statement completion.
At first, I thought Oracle had the same issue but further checking shows that the recursion limitation is isolated to SQL Server only!! The exact same data set works in Oracle like a charm.
Below is the "working" cte statement in SQL Server (up to 50 records)
with r (PresentationDate, Presentationid,Name,MaxSession,PresentationDay,rn,blocknum,pos,lastmaxrow) AS
(
select PresentationDate, Presentationid, Name, MaxSession, PresentationDay, rn,1,1,MaxSession
from presentation
where rn=1
union all
select u.PresentationDate, u.Presentationid, u.Name, u.MaxSession, u.PresentationDay, u.rn,
case
when r.pos=r.lastmaxrow or u.newblock=0 then
r.blocknum+1
else r.blocknum
end,
case
when r.pos = r.lastmaxrow or u.newblock=0 then 1
else r.pos+1
end,
case
when r.pos = r.lastmaxrow or u.newblock=0 then r.lastmaxrow
else r.MaxSession
end
from presentation u
join r
on u.Presentationid=r.Presentationid and u.rn=r.rn+1
)
select min(r.PresentationDate) as fromDate, max(r.PresentationDate) as todate,
r.Presentationid, r.Name
from r
group by r.Presentationid, r.Name, r.blocknum
order by r.Name, r.blocknum
So my questions are:
1) Is there something in my "working" code that could be improved to bypass the recursive limitation in SQL Server?
2) Is there a config switch in SQL Server that I can flip to allow recursive more than 100 times?
3) If the answer for the 2 above questions is no, is it possible to convert the recursive statement to non recursive statement without using cursor? I understand I may need multiple statements with other temporary table, but if the use of cursor is not necessary, I prefer not using it.
I have a full test sample in excel if needed. Since I do not know if I can upload it here, I attached an extract of my sample hopefully it is large enough to illustrate my point.
PresentationDate,PresentationDay,PresentationSession,PresentationID,Name,DayOfWeek,MaxSession,rn,newblock
2016-05-24 00:00:00.000,3,1,ID1,ABC,3,8,1,0
2016-05-24 00:00:00.000,3,2,ID1,ABC,3,8,2,1
2016-05-25 00:00:00.000,4,1,ID1,ABC,4,8,3,1
2016-05-25 00:00:00.000,4,2,ID1,ABC,4,8,4,1
2016-05-26 00:00:00.000,5,1,ID1,ABC,5,8,5,1
2016-05-26 00:00:00.000,5,2,ID1,ABC,5,8,6,1
2016-05-27 00:00:00.000,6,1,ID1,ABC,6,8,7,1
2016-05-27 00:00:00.000,6,2,ID1,ABC,6,8,8,1
2016-05-31 00:00:00.000,3,1,ID1,ABC,3,8,9,0
2016-05-31 00:00:00.000,3,2,ID1,ABC,3,8,10,1
2016-06-01 00:00:00.000,4,1,ID1,ABC,4,8,11,1
2016-06-01 00:00:00.000,4,2,ID1,ABC,4,8,12,1
2016-06-02 00:00:00.000,5,1,ID1,ABC,5,8,13,1
2016-06-02 00:00:00.000,5,2,ID1,ABC,5,8,14,1
2016-06-03 00:00:00.000,6,1,ID1,ABC,6,8,15,1
2016-06-03 00:00:00.000,6,2,ID1,ABC,6,8,16,1
2016-06-07 00:00:00.000,3,1,ID1,ABC,3,8,17,0
2016-06-07 00:00:00.000,3,2,ID1,ABC,3,8,18,1
2016-06-08 00:00:00.000,4,1,ID1,ABC,4,8,19,1
2016-06-08 00:00:00.000,4,2,ID1,ABC,4,8,20,1
2016-06-09 00:00:00.000,5,1,ID1,ABC,5,8,21,1
2016-06-09 00:00:00.000,5,2,ID1,ABC,5,8,22,1
2016-06-10 00:00:00.000,6,1,ID1,ABC,6,8,23,1
2016-06-10 00:00:00.000,6,2,ID1,ABC,6,8,24,1
2016-06-14 00:00:00.000,3,1,ID1,ABC,3,8,25,0
2016-06-14 00:00:00.000,3,2,ID1,ABC,3,8,26,1
2016-06-15 00:00:00.000,4,1,ID1,ABC,4,8,27,1
2016-06-15 00:00:00.000,4,2,ID1,ABC,4,8,28,1
2016-06-16 00:00:00.000,5,1,ID1,ABC,5,8,29,1
2016-06-16 00:00:00.000,5,2,ID1,ABC,5,8,30,1
2016-06-17 00:00:00.000,6,1,ID1,ABC,6,8,31,1
2016-06-17 00:00:00.000,6,2,ID1,ABC,6,8,32,1
2016-06-21 00:00:00.000,3,1,ID1,ABC,3,8,33,0
2016-06-21 00:00:00.000,3,2,ID1,ABC,3,8,34,1
2016-06-22 00:00:00.000,4,1,ID1,ABC,4,8,35,1
2016-06-22 00:00:00.000,4,2,ID1,ABC,4,8,36,1
2016-06-23 00:00:00.000,5,1,ID1,ABC,5,8,37,1
2016-06-23 00:00:00.000,5,2,ID1,ABC,5,8,38,1
2016-06-24 00:00:00.000,6,1,ID1,ABC,6,8,39,1
2016-06-24 00:00:00.000,6,2,ID1,ABC,6,8,40,1
2016-06-28 00:00:00.000,3,1,ID1,ABC,3,8,41,0
2016-06-28 00:00:00.000,3,2,ID1,ABC,3,8,42,1
2016-06-29 00:00:00.000,4,1,ID1,ABC,4,8,43,1
2016-06-29 00:00:00.000,4,2,ID1,ABC,4,8,44,1
2016-06-30 00:00:00.000,5,1,ID1,ABC,5,8,45,1
2016-06-30 00:00:00.000,5,2,ID1,ABC,5,8,46,1
2016-07-01 00:00:00.000,6,1,ID1,ABC,6,8,47,1
2016-07-01 00:00:00.000,6,2,ID1,ABC,6,8,48,1
2016-07-05 00:00:00.000,3,1,ID1,ABC,3,8,49,0
2016-07-05 00:00:00.000,3,2,ID1,ABC,3,8,50,1
2016-07-06 00:00:00.000,4,1,ID1,ABC,4,8,51,1
2016-07-06 00:00:00.000,4,2,ID1,ABC,4,8,52,1
2016-07-07 00:00:00.000,5,1,ID1,ABC,5,8,53,1
2016-07-07 00:00:00.000,5,2,ID1,ABC,5,8,54,1
2016-07-08 00:00:00.000,6,1,ID1,ABC,6,8,55,1
2016-07-08 00:00:00.000,6,2,ID1,ABC,6,8,56,1
2016-07-12 00:00:00.000,3,1,ID1,ABC,3,8,57,0
2016-07-12 00:00:00.000,3,2,ID1,ABC,3,8,58,1
2016-07-13 00:00:00.000,4,1,ID1,ABC,4,8,59,1
2016-07-13 00:00:00.000,4,2,ID1,ABC,4,8,60,1
2016-07-14 00:00:00.000,5,1,ID1,ABC,5,8,61,1
2016-07-14 00:00:00.000,5,2,ID1,ABC,5,8,62,1
2016-07-15 00:00:00.000,6,1,ID1,ABC,6,8,63,1
2016-07-15 00:00:00.000,6,2,ID1,ABC,6,8,64,1
2016-07-19 00:00:00.000,3,1,ID1,ABC,3,8,65,0
2016-07-19 00:00:00.000,3,2,ID1,ABC,3,8,66,1
2016-07-20 00:00:00.000,4,1,ID1,ABC,4,8,67,1
2016-07-20 00:00:00.000,4,2,ID1,ABC,4,8,68,1
2016-07-21 00:00:00.000,5,1,ID1,ABC,5,8,69,1
2016-07-21 00:00:00.000,5,2,ID1,ABC,5,8,70,1
2016-07-22 00:00:00.000,6,1,ID1,ABC,6,8,71,1
2016-07-22 00:00:00.000,6,2,ID1,ABC,6,8,72,1
2016-07-26 00:00:00.000,3,1,ID1,ABC,3,8,73,0
2016-07-26 00:00:00.000,3,2,ID1,ABC,3,8,74,1
2016-07-27 00:00:00.000,4,1,ID1,ABC,4,8,75,1
2016-07-27 00:00:00.000,4,2,ID1,ABC,4,8,76,1
2016-07-28 00:00:00.000,5,1,ID1,ABC,5,8,77,1
2016-07-28 00:00:00.000,5,2,ID1,ABC,5,8,78,1
2016-07-29 00:00:00.000,6,1,ID1,ABC,6,8,79,1
2016-07-29 00:00:00.000,6,2,ID1,ABC,6,8,80,1
2016-08-02 00:00:00.000,3,1,ID1,ABC,3,8,81,0
2016-08-02 00:00:00.000,3,2,ID1,ABC,3,8,82,1
2016-08-03 00:00:00.000,4,1,ID1,ABC,4,8,83,1
2016-08-03 00:00:00.000,4,2,ID1,ABC,4,8,84,1
2016-08-04 00:00:00.000,5,1,ID1,ABC,5,8,85,1
2016-08-04 00:00:00.000,5,2,ID1,ABC,5,8,86,1
2016-08-05 00:00:00.000,6,1,ID1,ABC,6,8,87,1
2016-08-05 00:00:00.000,6,2,ID1,ABC,6,8,88,1
2016-08-09 00:00:00.000,3,1,ID1,ABC,3,8,89,0
2016-08-09 00:00:00.000,3,2,ID1,ABC,3,8,90,1
2016-08-10 00:00:00.000,4,1,ID1,ABC,4,8,91,1
2016-08-10 00:00:00.000,4,2,ID1,ABC,4,8,92,1
2016-08-11 00:00:00.000,5,1,ID1,ABC,5,8,93,1
2016-08-11 00:00:00.000,5,2,ID1,ABC,5,8,94,1
2016-08-12 00:00:00.000,6,1,ID1,ABC,6,8,95,1
2016-08-12 00:00:00.000,6,2,ID1,ABC,6,8,96,1
2016-08-16 00:00:00.000,3,1,ID1,ABC,3,8,97,0
2016-08-16 00:00:00.000,3,2,ID1,ABC,3,8,98,1
2016-08-17 00:00:00.000,4,1,ID1,ABC,4,8,99,1
2016-08-17 00:00:00.000,4,2,ID1,ABC,4,8,100,1
2016-08-18 00:00:00.000,5,1,ID1,ABC,5,8,101,1
2016-08-18 00:00:00.000,5,2,ID1,ABC,5,8,102,1
2016-08-19 00:00:00.000,6,1,ID1,ABC,6,8,103,1
2016-08-19 00:00:00.000,6,2,ID1,ABC,6,8,104,1
2016-08-23 00:00:00.000,3,1,ID1,ABC,3,8,105,0
2016-08-23 00:00:00.000,3,2,ID1,ABC,3,8,106,1
2016-08-24 00:00:00.000,4,1,ID1,ABC,4,8,107,1
2016-08-24 00:00:00.000,4,2,ID1,ABC,4,8,108,1
2016-08-25 00:00:00.000,5,1,ID1,ABC,5,8,109,1
2016-08-25 00:00:00.000,5,2,ID1,ABC,5,8,110,1
2016-08-26 00:00:00.000,6,1,ID1,ABC,6,8,111,1
2016-08-26 00:00:00.000,6,2,ID1,ABC,6,8,112,1
2016-08-30 00:00:00.000,3,1,ID1,ABC,3,8,113,0
2016-08-30 00:00:00.000,3,2,ID1,ABC,3,8,114,1
2016-08-31 00:00:00.000,4,1,ID1,ABC,4,8,115,1
2016-08-31 00:00:00.000,4,2,ID1,ABC,4,8,116,1
2016-09-01 00:00:00.000,5,1,ID1,ABC,5,8,117,1
2016-09-01 00:00:00.000,5,2,ID1,ABC,5,8,118,1
2016-09-02 00:00:00.000,6,1,ID1,ABC,6,8,119,1
2016-09-02 00:00:00.000,6,2,ID1,ABC,6,8,120,1
2016-09-06 00:00:00.000,3,1,ID1,ABC,3,8,121,0
2016-09-06 00:00:00.000,3,2,ID1,ABC,3,8,122,1
2016-09-07 00:00:00.000,4,1,ID1,ABC,4,8,123,1
2016-09-07 00:00:00.000,4,2,ID1,ABC,4,8,124,1
2016-09-08 00:00:00.000,5,1,ID1,ABC,5,8,125,1
2016-09-08 00:00:00.000,5,2,ID1,ABC,5,8,126,1
2016-09-09 00:00:00.000,6,1,ID1,ABC,6,8,127,1
2016-09-09 00:00:00.000,6,2,ID1,ABC,6,8,128,1
2016-09-13 00:00:00.000,3,1,ID1,ABC,3,8,129,0
2016-09-13 00:00:00.000,3,2,ID1,ABC,3,8,130,1
2016-09-14 00:00:00.000,4,1,ID1,ABC,4,8,131,1
2016-09-14 00:00:00.000,4,2,ID1,ABC,4,8,132,1
2016-09-15 00:00:00.000,5,1,ID1,ABC,5,8,133,1
2016-09-15 00:00:00.000,5,2,ID1,ABC,5,8,134,1
2016-09-16 00:00:00.000,6,1,ID1,ABC,6,8,135,1
2016-09-16 00:00:00.000,6,2,ID1,ABC,6,8,136,1
2016-09-20 00:00:00.000,3,1,ID1,ABC,3,8,137,0
2016-09-20 00:00:00.000,3,2,ID1,ABC,3,8,138,1
2016-09-21 00:00:00.000,4,1,ID1,ABC,4,8,139,1
2016-09-21 00:00:00.000,4,2,ID1,ABC,4,8,140,1
2016-09-22 00:00:00.000,5,1,ID1,ABC,5,8,141,1
2016-09-22 00:00:00.000,5,2,ID1,ABC,5,8,142,1
2016-09-23 00:00:00.000,6,1,ID1,ABC,6,8,143,1
2016-09-23 00:00:00.000,6,2,ID1,ABC,6,8,144,1
2016-09-27 00:00:00.000,3,1,ID1,ABC,3,8,145,0
2016-09-27 00:00:00.000,3,2,ID1,ABC,3,8,146,1
2016-09-28 00:00:00.000,4,1,ID1,ABC,4,8,147,1
2016-09-28 00:00:00.000,4,2,ID1,ABC,4,8,148,1
2016-09-29 00:00:00.000,5,1,ID1,ABC,5,8,149,1
2016-09-29 00:00:00.000,5,2,ID1,ABC,5,8,150,1
2016-09-30 00:00:00.000,6,1,ID1,ABC,6,8,151,1
2016-09-30 00:00:00.000,6,2,ID1,ABC,6,8,152,1
2016-10-04 00:00:00.000,3,1,ID1,ABC,3,8,153,0
2016-10-04 00:00:00.000,3,2,ID1,ABC,3,8,154,1
2016-10-05 00:00:00.000,4,1,ID1,ABC,4,8,155,1
2016-10-05 00:00:00.000,4,2,ID1,ABC,4,8,156,1
2016-10-06 00:00:00.000,5,1,ID1,ABC,5,8,157,1
2016-10-06 00:00:00.000,5,2,ID1,ABC,5,8,158,1
2016-10-07 00:00:00.000,6,1,ID1,ABC,6,8,159,1
2016-10-07 00:00:00.000,6,2,ID1,ABC,6,8,160,1
2016-10-11 00:00:00.000,3,1,ID1,ABC,3,8,161,0
2016-10-11 00:00:00.000,3,2,ID1,ABC,3,8,162,1
2016-10-12 00:00:00.000,4,1,ID1,ABC,4,8,163,1
2016-10-12 00:00:00.000,4,2,ID1,ABC,4,8,164,1
2016-10-13 00:00:00.000,5,1,ID1,ABC,5,8,165,1
2016-10-13 00:00:00.000,5,2,ID1,ABC,5,8,166,1
2016-10-14 00:00:00.000,6,1,ID1,ABC,6,8,167,1
2016-10-14 00:00:00.000,6,2,ID1,ABC,6,8,168,1
2016-10-18 00:00:00.000,3,1,ID1,ABC,3,8,169,0
2016-10-18 00:00:00.000,3,2,ID1,ABC,3,8,170,1
2016-10-19 00:00:00.000,4,1,ID1,ABC,4,8,171,1
2016-10-19 00:00:00.000,4,2,ID1,ABC,4,8,172,1
2016-10-20 00:00:00.000,5,1,ID1,ABC,5,8,173,1
2016-10-20 00:00:00.000,5,2,ID1,ABC,5,8,174,1
2016-10-21 00:00:00.000,6,1,ID1,ABC,6,8,175,1
2016-10-21 00:00:00.000,6,2,ID1,ABC,6,8,176,1
2016-10-25 00:00:00.000,3,1,ID1,ABC,3,8,177,0
2016-10-25 00:00:00.000,3,2,ID1,ABC,3,8,178,1
2016-10-26 00:00:00.000,4,1,ID1,ABC,4,8,179,1
2016-10-26 00:00:00.000,4,2,ID1,ABC,4,8,180,1
2016-10-27 00:00:00.000,5,1,ID1,ABC,5,8,181,1
2016-10-27 00:00:00.000,5,2,ID1,ABC,5,8,182,1
2016-10-28 00:00:00.000,6,1,ID1,ABC,6,8,183,1
2016-10-28 00:00:00.000,6,2,ID1,ABC,6,8,184,1
2016-11-01 00:00:00.000,3,1,ID1,ABC,3,8,185,0
2016-11-01 00:00:00.000,3,2,ID1,ABC,3,8,186,1
2016-11-02 00:00:00.000,4,1,ID1,ABC,4,8,187,1
2016-11-02 00:00:00.000,4,2,ID1,ABC,4,8,188,1
2016-11-03 00:00:00.000,5,1,ID1,ABC,5,8,189,1
2016-11-03 00:00:00.000,5,2,ID1,ABC,5,8,190,1
2016-11-04 00:00:00.000,6,1,ID1,ABC,6,8,191,1
2016-11-04 00:00:00.000,6,2,ID1,ABC,6,8,192,1
2016-11-08 00:00:00.000,3,1,ID1,ABC,3,8,193,0
2016-11-08 00:00:00.000,3,2,ID1,ABC,3,8,194,1
2016-11-09 00:00:00.000,4,1,ID1,ABC,4,8,195,1
2016-11-09 00:00:00.000,4,2,ID1,ABC,4,8,196,1
2016-11-10 00:00:00.000,5,1,ID1,ABC,5,8,197,1
2016-11-10 00:00:00.000,5,2,ID1,ABC,5,8,198,1
2016-11-11 00:00:00.000,6,1,ID1,ABC,6,8,199,1
2016-11-11 00:00:00.000,6,2,ID1,ABC,6,8,200,1
In SQL Server you can bypass 100 iterations default limitation by specifying OPTION (MAXRECURSION X) with your query. Where X is maximum number of iterations, and it can have values from 0 (no limitation) up to 32767 (maximum defined limitation).
If you are uncertain how many iterations you might expect or amount of expected iterations exceeds 32767 then you might consider using MAXRECURSION 0 option.
with r (PresentationDate, Presentationid,Name,MaxSession,PresentationDay,rn,blocknum,pos,lastmaxrow) AS
(
select PresentationDate, Presentationid, Name, MaxSession, PresentationDay, rn,1,1,MaxSession
from presentation
where rn=1
union all
select u.PresentationDate, u.Presentationid, u.Name, u.MaxSession, u.PresentationDay, u.rn,
case
when r.pos=r.lastmaxrow or u.newblock=0 then
r.blocknum+1
else r.blocknum
end,
case
when r.pos = r.lastmaxrow or u.newblock=0 then 1
else r.pos+1
end,
case
when r.pos = r.lastmaxrow or u.newblock=0 then r.lastmaxrow
else r.MaxSession
end
from presentation u
join r
on u.Presentationid=r.Presentationid and u.rn=r.rn+1
)
select min(r.PresentationDate) as fromDate, max(r.PresentationDate) as todate,
r.Presentationid, r.Name
from r
group by r.Presentationid, r.Name, r.blocknum
order by r.Name, r.blocknum
OPTION (MAXRECURSION 0)
You can read about MAXRECURSION in context of CTE here
Gaps and Islands
Here is the minimum query that demonstrate the concept.
There are plenty of tutorials that explain this type of problem in detail.
select PresentationID
,min(PresentationDate) as from_date
,max(PresentationDate) as to_date
from (select PresentationID
,PresentationDate
,dense_rank () over
(
partition by PresentationID
order by PresentationDate
) as dr
from presentation
) p
group by PresentationID
,dateadd(day,-dr,PresentationDate)
order by PresentationID
,to_date
+----------------+------------+------------+
| PresentationID | from_date | to_date |
+----------------+------------+------------+
| ID1 | 2016-05-24 | 2016-05-27 |
| ID1 | 2016-05-31 | 2016-06-03 |
| ID1 | 2016-06-07 | 2016-06-10 |
| ID1 | 2016-06-14 | 2016-06-17 |
| ID1 | 2016-06-21 | 2016-06-24 |
| ID1 | 2016-06-28 | 2016-07-01 |
| ID1 | 2016-07-05 | 2016-07-08 |
| ID1 | 2016-07-12 | 2016-07-15 |
| ID1 | 2016-07-19 | 2016-07-22 |
| ID1 | 2016-07-26 | 2016-07-29 |
| ID1 | 2016-08-02 | 2016-08-05 |
| ID1 | 2016-08-09 | 2016-08-12 |
| ID1 | 2016-08-16 | 2016-08-19 |
| ID1 | 2016-08-23 | 2016-08-26 |
...
Here are some data That will help you to understand what's going on here.
+----------------+------------------+----+------------+
| PresentationID | PresentationDate | dr | dateadd |
+----------------+------------------+----+------------+
| ID1 | 2016-05-24 | 1 | 2016-05-23 |
| ID1 | 2016-05-24 | 1 | 2016-05-23 |
| ID1 | 2016-05-25 | 2 | 2016-05-23 |
| ID1 | 2016-05-25 | 2 | 2016-05-23 |
| ID1 | 2016-05-26 | 3 | 2016-05-23 |
| ID1 | 2016-05-26 | 3 | 2016-05-23 |
| ID1 | 2016-05-27 | 4 | 2016-05-23 |
| ID1 | 2016-05-27 | 4 | 2016-05-23 |
| ID1 | 2016-05-31 | 5 | 2016-05-26 |
| ID1 | 2016-05-31 | 5 | 2016-05-26 |
| ID1 | 2016-06-01 | 6 | 2016-05-26 |
| ID1 | 2016-06-01 | 6 | 2016-05-26 |
| ID1 | 2016-06-02 | 7 | 2016-05-26 |
| ID1 | 2016-06-02 | 7 | 2016-05-26 |
| ID1 | 2016-06-03 | 8 | 2016-05-26 |
| ID1 | 2016-06-03 | 8 | 2016-05-26 |
| ID1 | 2016-06-07 | 9 | 2016-05-29 |
| ID1 | 2016-06-07 | 9 | 2016-05-29 |
| ID1 | 2016-06-08 | 10 | 2016-05-29 |
| ID1 | 2016-06-08 | 10 | 2016-05-29 |
...

SQL - Compare rows by id, date and amount

I need to SELECT a row in which issue_date = maturity_date of another row with same id, and same amount_usd.
I tried with self join, but I do not get right result.
Here is a simplified version of my table:
ID ISSUE_DATE MATURITY_DATE AMOUNT_USD
1 2010-01-01 00:00:00.000 2015-12-01 00:00:00.000 5000
1 2010-01-01 00:00:00.000 2001-09-19 00:00:00.000 700
2 2014-04-09 00:00:00.000 2019-04-09 00:00:00.000 400
1 2015-12-01 00:00:00.000 2016-12-31 00:00:00.000 5000
5 2015-02-24 00:00:00.000 2015-02-24 00:00:00.000 8000
4 2012-11-29 00:00:00.000 2015-11-29 00:00:00.000 10000
3 2015-01-21 00:00:00.000 2018-01-21 00:00:00.000 17500
2 2015-02-02 00:00:00.000 2015-12-05 00:00:00.000 12000
1 2015-01-12 00:00:00.000 2018-01-12 00:00:00.000 18000
2 2015-12-05 00:00:00.000 2016-01-10 00:00:00.000 12000
Result should be:
ID ISSUE_DATE MATURITY_DATE AMOUNT_USD
1 2015-12-01 00:00:00.000 2016-12-31 00:00:00.000 5000
2 2015-12-05 00:00:00.000 2016-01-10 00:00:00.000 12000
Thanks in advance!
Do following: http://sqlfiddle.com/#!6/c0a02/1
select a.id, a.issue_date, a.maturity_date, a.amount_usd
from tbl a
inner join tbl b
on a.id = b.id
and a.maturity_date = b.issue_date
-- added to prevent same maturity date and issue date
where a.maturity_date <> a.issue_date
Output:
| id | issue_date | maturity_date | amount_usd |
|----|----------------------------|----------------------------|------------|
| 1 | January, 01 2010 00:00:00 | December, 01 2015 00:00:00 | 5000 |
| 2 | February, 02 2015 00:00:00 | December, 05 2015 00:00:00 | 12000 |