TSQL: Grouping continuous timeslots together Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern) The Ask Question Wizard is Live! Data science time! April 2019 and salary with experienceConverting a table with a key and comment field into a key and row for every word in the column fieldHow do I get list of all tables in a database using TSQL?Select columns from result set of stored procedureTSQL Default Minimum DateTimeReplace a newline in TSQLSQL update query using joinstsql merge columns into one tabletsql -group by by max datetime in rowsTSQL Continuous CountersTsql Inserting Unordered SequenceHow to group data into 10 second intevals?

How do you keep chess fun when your opponent constantly beats you?

The following signatures were invalid: EXPKEYSIG 1397BC53640DB551

Is above average number of years spent on PhD considered a red flag in future academia or industry positions?

Losing the Initialization Vector in Cipher Block Chaining

Can't figure this one out.. What is the missing box?

Why does tar appear to skip file contents when output file is /dev/null?

Limit for e and 1/e

Replacing HDD with SSD; what about non-APFS/APFS?

When is phishing education going too far?

How to say that you spent the night with someone, you were only sleeping and nothing else?

How to dynamically generate the hash value of a file while it gets downloaded from any website?

Strange behaviour of Check

Stars Make Stars

What did Darwin mean by 'squib' here?

What do you call a plan that's an alternative plan in case your initial plan fails?

Single author papers against my advisor's will?

How to market an anarchic city as a tourism spot to people living in civilized areas?

Does a C shift expression have unsigned type? Why would Splint warn about a right-shift?

Interesting examples of non-locally compact topological groups

Working around an AWS network ACL rule limit

A constraint that implies convexity

Using "nakedly" instead of "with nothing on"

What is the largest species of polychaete?

Simulating Exploding Dice



TSQL: Grouping continuous timeslots together



Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)
The Ask Question Wizard is Live!
Data science time! April 2019 and salary with experienceConverting a table with a key and comment field into a key and row for every word in the column fieldHow do I get list of all tables in a database using TSQL?Select columns from result set of stored procedureTSQL Default Minimum DateTimeReplace a newline in TSQLSQL update query using joinstsql merge columns into one tabletsql -group by by max datetime in rowsTSQL Continuous CountersTsql Inserting Unordered SequenceHow to group data into 10 second intevals?



.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








1















I have to group continuous timeslots together:



Example:



DECLARE @TEST as Table (ID int, tFrom datetime, tUntil dateTime)
insert into @TEST Values (1,'2019-1-1 12:00', '2019-1-1 13:00')
insert into @TEST Values (1,'2019-1-1 13:00', '2019-1-1 14:00')
insert into @TEST Values (1,'2019-1-1 14:00', '2019-1-1 16:00')
insert into @TEST Values (1,'2019-1-1 18:00', '2019-1-1 19:00')
insert into @TEST Values (1,'2019-1-1 19:00', '2019-1-1 20:00')
insert into @TEST Values (1,'2019-1-1 20:00', '2019-1-1 21:00')
insert into @TEST Values (1,'2019-1-1 22:00', '2019-1-1 23:00')
insert into @TEST Values (2,'2019-1-1 12:00', '2019-1-1 13:00')
insert into @TEST Values (2,'2019-1-1 13:00', '2019-1-1 14:00')
insert into @TEST Values (2,'2019-1-1 14:00', '2019-1-1 16:00')
insert into @TEST Values (2,'2019-1-1 18:00', '2019-1-1 19:00')
insert into @TEST Values (2,'2019-1-1 19:00', '2019-1-1 20:00')
insert into @TEST Values (2,'2019-1-1 20:00', '2019-1-1 21:00')
insert into @TEST Values (2,'2019-1-1 22:00', '2019-1-1 23:00')


Expected result:



1; 2019-1-1 12:00; 2019-1-1 16:00
1; 2019-1-1 18:00; 2019-1-1 21:00
1; 2019-1-1 22:00; 2019-1-1 23:00
2; 2019-1-1 12:00; 2019-1-1 16:00
2; 2019-1-1 18:00; 2019-1-1 21:00
2; 2019-1-1 22:00; 2019-1-1 23:00









share|improve this question
























  • Kudos for posting proper sample data and desired results. If you would have been a better question if you would also post your current attempts at solving this problem.

    – Zohar Peled
    Mar 22 at 8:52











  • Is the difference between tFrom and tUntil always one hour?

    – Zohar Peled
    Mar 22 at 9:44

















1















I have to group continuous timeslots together:



Example:



DECLARE @TEST as Table (ID int, tFrom datetime, tUntil dateTime)
insert into @TEST Values (1,'2019-1-1 12:00', '2019-1-1 13:00')
insert into @TEST Values (1,'2019-1-1 13:00', '2019-1-1 14:00')
insert into @TEST Values (1,'2019-1-1 14:00', '2019-1-1 16:00')
insert into @TEST Values (1,'2019-1-1 18:00', '2019-1-1 19:00')
insert into @TEST Values (1,'2019-1-1 19:00', '2019-1-1 20:00')
insert into @TEST Values (1,'2019-1-1 20:00', '2019-1-1 21:00')
insert into @TEST Values (1,'2019-1-1 22:00', '2019-1-1 23:00')
insert into @TEST Values (2,'2019-1-1 12:00', '2019-1-1 13:00')
insert into @TEST Values (2,'2019-1-1 13:00', '2019-1-1 14:00')
insert into @TEST Values (2,'2019-1-1 14:00', '2019-1-1 16:00')
insert into @TEST Values (2,'2019-1-1 18:00', '2019-1-1 19:00')
insert into @TEST Values (2,'2019-1-1 19:00', '2019-1-1 20:00')
insert into @TEST Values (2,'2019-1-1 20:00', '2019-1-1 21:00')
insert into @TEST Values (2,'2019-1-1 22:00', '2019-1-1 23:00')


Expected result:



1; 2019-1-1 12:00; 2019-1-1 16:00
1; 2019-1-1 18:00; 2019-1-1 21:00
1; 2019-1-1 22:00; 2019-1-1 23:00
2; 2019-1-1 12:00; 2019-1-1 16:00
2; 2019-1-1 18:00; 2019-1-1 21:00
2; 2019-1-1 22:00; 2019-1-1 23:00









share|improve this question
























  • Kudos for posting proper sample data and desired results. If you would have been a better question if you would also post your current attempts at solving this problem.

    – Zohar Peled
    Mar 22 at 8:52











  • Is the difference between tFrom and tUntil always one hour?

    – Zohar Peled
    Mar 22 at 9:44













1












1








1








I have to group continuous timeslots together:



Example:



DECLARE @TEST as Table (ID int, tFrom datetime, tUntil dateTime)
insert into @TEST Values (1,'2019-1-1 12:00', '2019-1-1 13:00')
insert into @TEST Values (1,'2019-1-1 13:00', '2019-1-1 14:00')
insert into @TEST Values (1,'2019-1-1 14:00', '2019-1-1 16:00')
insert into @TEST Values (1,'2019-1-1 18:00', '2019-1-1 19:00')
insert into @TEST Values (1,'2019-1-1 19:00', '2019-1-1 20:00')
insert into @TEST Values (1,'2019-1-1 20:00', '2019-1-1 21:00')
insert into @TEST Values (1,'2019-1-1 22:00', '2019-1-1 23:00')
insert into @TEST Values (2,'2019-1-1 12:00', '2019-1-1 13:00')
insert into @TEST Values (2,'2019-1-1 13:00', '2019-1-1 14:00')
insert into @TEST Values (2,'2019-1-1 14:00', '2019-1-1 16:00')
insert into @TEST Values (2,'2019-1-1 18:00', '2019-1-1 19:00')
insert into @TEST Values (2,'2019-1-1 19:00', '2019-1-1 20:00')
insert into @TEST Values (2,'2019-1-1 20:00', '2019-1-1 21:00')
insert into @TEST Values (2,'2019-1-1 22:00', '2019-1-1 23:00')


Expected result:



1; 2019-1-1 12:00; 2019-1-1 16:00
1; 2019-1-1 18:00; 2019-1-1 21:00
1; 2019-1-1 22:00; 2019-1-1 23:00
2; 2019-1-1 12:00; 2019-1-1 16:00
2; 2019-1-1 18:00; 2019-1-1 21:00
2; 2019-1-1 22:00; 2019-1-1 23:00









share|improve this question
















I have to group continuous timeslots together:



Example:



DECLARE @TEST as Table (ID int, tFrom datetime, tUntil dateTime)
insert into @TEST Values (1,'2019-1-1 12:00', '2019-1-1 13:00')
insert into @TEST Values (1,'2019-1-1 13:00', '2019-1-1 14:00')
insert into @TEST Values (1,'2019-1-1 14:00', '2019-1-1 16:00')
insert into @TEST Values (1,'2019-1-1 18:00', '2019-1-1 19:00')
insert into @TEST Values (1,'2019-1-1 19:00', '2019-1-1 20:00')
insert into @TEST Values (1,'2019-1-1 20:00', '2019-1-1 21:00')
insert into @TEST Values (1,'2019-1-1 22:00', '2019-1-1 23:00')
insert into @TEST Values (2,'2019-1-1 12:00', '2019-1-1 13:00')
insert into @TEST Values (2,'2019-1-1 13:00', '2019-1-1 14:00')
insert into @TEST Values (2,'2019-1-1 14:00', '2019-1-1 16:00')
insert into @TEST Values (2,'2019-1-1 18:00', '2019-1-1 19:00')
insert into @TEST Values (2,'2019-1-1 19:00', '2019-1-1 20:00')
insert into @TEST Values (2,'2019-1-1 20:00', '2019-1-1 21:00')
insert into @TEST Values (2,'2019-1-1 22:00', '2019-1-1 23:00')


Expected result:



1; 2019-1-1 12:00; 2019-1-1 16:00
1; 2019-1-1 18:00; 2019-1-1 21:00
1; 2019-1-1 22:00; 2019-1-1 23:00
2; 2019-1-1 12:00; 2019-1-1 16:00
2; 2019-1-1 18:00; 2019-1-1 21:00
2; 2019-1-1 22:00; 2019-1-1 23:00






tsql






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 22 at 7:53









oguz ismail

5,73841327




5,73841327










asked Mar 22 at 7:23









tommiredtommired

153




153












  • Kudos for posting proper sample data and desired results. If you would have been a better question if you would also post your current attempts at solving this problem.

    – Zohar Peled
    Mar 22 at 8:52











  • Is the difference between tFrom and tUntil always one hour?

    – Zohar Peled
    Mar 22 at 9:44

















  • Kudos for posting proper sample data and desired results. If you would have been a better question if you would also post your current attempts at solving this problem.

    – Zohar Peled
    Mar 22 at 8:52











  • Is the difference between tFrom and tUntil always one hour?

    – Zohar Peled
    Mar 22 at 9:44
















Kudos for posting proper sample data and desired results. If you would have been a better question if you would also post your current attempts at solving this problem.

– Zohar Peled
Mar 22 at 8:52





Kudos for posting proper sample data and desired results. If you would have been a better question if you would also post your current attempts at solving this problem.

– Zohar Peled
Mar 22 at 8:52













Is the difference between tFrom and tUntil always one hour?

– Zohar Peled
Mar 22 at 9:44





Is the difference between tFrom and tUntil always one hour?

– Zohar Peled
Mar 22 at 9:44












2 Answers
2






active

oldest

votes


















0














This is a classing gaps-and-islands problem.
The key here is how to identify the groups.



If the difference between tFrom and tUntil is always exactly one hour, you can ignore the tUntil and work only based on the differences between tFrom of different records.

Use a common table expression to identify the groups, and then select min(tFrom) and max(tUntil) from it, grouped by id and group.



What you do is calculate the hours difference between the tFrom and some fixed date, and you subtract that value from row_number ordered by tFrom (and partitioned by id in this case).



This means that consecutive values of tFrom will get the same group key (consecutive here means by the hour in this case):



WITH CTE AS
(
SELECT ID,
tFrom,
tUntil,
ROW_NUMBER() OVER(PARTITION BY id ORDER BY tFrom) -
DATEDIFF(HOUR, '2019-01-01', tFrom) As grp
FROM @Test
)

SELECT ID,
MIN(tFrom) As tFrom,
MAX(tUntil) As tUntil
FROM CTE
GROUP BY ID, grp
ORDER BY Id, tFrom


If the difference between tFrom and tUntill is not fixed, than it's going to be more cumbersome to identify the groups.

I came up with a solution involving three common table expressions - the first is to get the datediff between the current row's tUntill and the next row's tFrom, then calculate a group divider based on previous row's difference, and then calculate the group id based on sums of the dividers:



WITH CTE1 AS
(
SELECT ID,
tFrom,
tUntil,
DATEDIFF(HOUR, tUntil, LEAD(tFrom) OVER(PARTITION BY id ORDER BY tFrom)) As DiffNext
FROM @Test
), CTE2 AS
(
SELECT ID,
tFrom,
tUntil,
ISNULL(SIGN(LAG(DiffNext) OVER(PARTITION BY id ORDER BY tFrom)), 1) AS GroupDivider
FROM CTE1
), CTE3 AS
(
SELECT ID,
tFrom,
tUntil,
SUM(GroupDivider) OVER(PARTITION BY id ORDER BY tFrom) As GroupId
FROM CTE2
)

SELECT ID,
MIN(tFrom) As tFrom,
MAX(tUntil) As tUntil
FROM CTE3
GROUP BY ID, GroupId
ORDER BY ID, tFrom





share|improve this answer

























  • Dear Zohar, thanks a lot! This is working perfectly. As I am not so experienced with this stuff I will try to understand what you did here. Magic :-).

    – tommired
    Mar 22 at 11:06











  • If you need a clarification simply ask... Glad to help :-)

    – Zohar Peled
    Mar 22 at 11:18











  • Hi @ZoharPeled, this solution will not work if you have overlap in the ranges of the time. For example try to add another row insert into TEST Values (1,'2019-1-1 10:00', '2019-1-1 23:00') ,and now you supposed to get only one row in the result set for ID = 1 but you still get three rows

    – Ronen Ariely
    Mar 22 at 13:19






  • 1





    @RonenAriely I've seen Alan around here. we've occasionally posted answers to same questions, but I don't remember getting downvotes on these question. My point is that the downvote could have been from anyone with high enough reputation (IIRC 125) - but I don't think it was from Alan. He does seem to have a tendency for self promoting, but not at the expense of other SO members. I used to get pissed anytime one of my answers was downvoted but I've realized that even when I know I'm correct, some people will still think I'm wrong, and there's nothing I can do about it [to be continued...]

    – Zohar Peled
    Mar 24 at 5:50






  • 1





    Hi @ZoharPeled, for you anything :-). I will provide a full solution(s) - there are several options, the common option which is using the "Gaps and Islands" logic,which I mentioned before, and there is my secrete solution which was not yet publish in blog but I did mentioned it several times in lectures and in forums... It is 00:30 AM now and I go to sleep. I hope to have time tomorrow evening to post a blog with the solution(s).P.s @ZoharPeled you can always contact me in private on Facebook. No need to wait that I will come here why mistake :-)

    – Ronen Ariely
    Mar 24 at 22:31


















0














Good day,



In order to have a flexible solution which cover overlap in the ranges of the time, there are several solutions which we can use. "Gaps & Islands" approach is not the best (from the performance point of view), but it will work, and there are worse options as well (like using loop/cursor). Since "Gaps & Islands" was the phrase that mentioned in the comments and in the solution which was discuss in the comments, l will first show this solution in short.



The solution using the "Gaps & Islands" approach is based on two steps (one query which use CTE). First, you split the ranges into "points in time". Next using "numbers" table or better in this case a "Times" table, you can get the final result SET by finding the gaps between the points, which is classic "Gaps & Islands" problem.



I HIGHLY recommend to follow the post, which I published, and follow it from start to end! There are limitations and disadvantages for this approach, which you must understand. Moreover, the post present the "way of thinking" and how we solve problems like this one step-by-step.



In the post I start with the simplest case of ranges of integers, for example 2-4, 6-8, 8-10, 13-14 which should be grouped into 2-4, 6-10, 13-14.



Next I move to explain issue related to the resolution of space between the ranges, and I present a solution for Ranges of Decimal numbers, which cover the issue.



Finally, using the solution which I presented in detail for INTEGERS, I presented a solution for "Grouping continuous time-slots together", which was the original question in the forum.



Note! The solution which presented here is probably the one which I recommend to use in production. In my next post I published a totally different approach using my personal trick, which can improve performance dramatically.



In short, for the sake of the discussion I will create a Times table (you can use Numbers table directly if you really want). Notice that I create the Times table using a Numbers table.



DROP TABLE IF EXISTS Times
GO
SELECT DT = DATEADD(MINUTE, N*10, '2010-01-01')
INTO Times
FROM Numbers
GO
CREATE CLUSTERED INDEX IX_DT ON Times(DT)
GO
SELECT TOP 1000 DT from Times
GO


and using this table we can solve the issue



;With MyCTE01 as (
SELECT DISTINCT ID, DT
FROM TEST t
INNER JOIN Times dt ON DT between tFrom and tUntil
)
,MyCTE02 as(
SELECT ID, DT,
MyGroup =
DATEDIFF(MINUTE,
DATEADD(MINUTE, 10 * ROW_NUMBER()OVER(PARTITION BY ID ORDER BY ID,DT),0),
DT
)
from MyCTE01
--order by ID,DT
)
SELECT ID, MIN(DT) tFrom, MAX(DT) tUntil
FROM MyCTE02
GROUP BY ID, MyGroup
ORDER BY ID, tFrom
GO


Note! I highly recommend to check the second post (Part 2) before choosing the solution that fit you in production.



I hope that this cover the discussion and that it was helpful






share|improve this answer

























  • Hi @ZoharPeled, you are welcome to check the solutions (i published here the "Gaps & Islands" approach as requested, and I published a post about another approach.

    – Ronen Ariely
    Apr 3 at 13:18











  • Hi @tommired, please inform me if something is not clear. I will be happy to elaborate more :-)

    – Ronen Ariely
    Apr 3 at 13:19











Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55294707%2ftsql-grouping-continuous-timeslots-together%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









0














This is a classing gaps-and-islands problem.
The key here is how to identify the groups.



If the difference between tFrom and tUntil is always exactly one hour, you can ignore the tUntil and work only based on the differences between tFrom of different records.

Use a common table expression to identify the groups, and then select min(tFrom) and max(tUntil) from it, grouped by id and group.



What you do is calculate the hours difference between the tFrom and some fixed date, and you subtract that value from row_number ordered by tFrom (and partitioned by id in this case).



This means that consecutive values of tFrom will get the same group key (consecutive here means by the hour in this case):



WITH CTE AS
(
SELECT ID,
tFrom,
tUntil,
ROW_NUMBER() OVER(PARTITION BY id ORDER BY tFrom) -
DATEDIFF(HOUR, '2019-01-01', tFrom) As grp
FROM @Test
)

SELECT ID,
MIN(tFrom) As tFrom,
MAX(tUntil) As tUntil
FROM CTE
GROUP BY ID, grp
ORDER BY Id, tFrom


If the difference between tFrom and tUntill is not fixed, than it's going to be more cumbersome to identify the groups.

I came up with a solution involving three common table expressions - the first is to get the datediff between the current row's tUntill and the next row's tFrom, then calculate a group divider based on previous row's difference, and then calculate the group id based on sums of the dividers:



WITH CTE1 AS
(
SELECT ID,
tFrom,
tUntil,
DATEDIFF(HOUR, tUntil, LEAD(tFrom) OVER(PARTITION BY id ORDER BY tFrom)) As DiffNext
FROM @Test
), CTE2 AS
(
SELECT ID,
tFrom,
tUntil,
ISNULL(SIGN(LAG(DiffNext) OVER(PARTITION BY id ORDER BY tFrom)), 1) AS GroupDivider
FROM CTE1
), CTE3 AS
(
SELECT ID,
tFrom,
tUntil,
SUM(GroupDivider) OVER(PARTITION BY id ORDER BY tFrom) As GroupId
FROM CTE2
)

SELECT ID,
MIN(tFrom) As tFrom,
MAX(tUntil) As tUntil
FROM CTE3
GROUP BY ID, GroupId
ORDER BY ID, tFrom





share|improve this answer

























  • Dear Zohar, thanks a lot! This is working perfectly. As I am not so experienced with this stuff I will try to understand what you did here. Magic :-).

    – tommired
    Mar 22 at 11:06











  • If you need a clarification simply ask... Glad to help :-)

    – Zohar Peled
    Mar 22 at 11:18











  • Hi @ZoharPeled, this solution will not work if you have overlap in the ranges of the time. For example try to add another row insert into TEST Values (1,'2019-1-1 10:00', '2019-1-1 23:00') ,and now you supposed to get only one row in the result set for ID = 1 but you still get three rows

    – Ronen Ariely
    Mar 22 at 13:19






  • 1





    @RonenAriely I've seen Alan around here. we've occasionally posted answers to same questions, but I don't remember getting downvotes on these question. My point is that the downvote could have been from anyone with high enough reputation (IIRC 125) - but I don't think it was from Alan. He does seem to have a tendency for self promoting, but not at the expense of other SO members. I used to get pissed anytime one of my answers was downvoted but I've realized that even when I know I'm correct, some people will still think I'm wrong, and there's nothing I can do about it [to be continued...]

    – Zohar Peled
    Mar 24 at 5:50






  • 1





    Hi @ZoharPeled, for you anything :-). I will provide a full solution(s) - there are several options, the common option which is using the "Gaps and Islands" logic,which I mentioned before, and there is my secrete solution which was not yet publish in blog but I did mentioned it several times in lectures and in forums... It is 00:30 AM now and I go to sleep. I hope to have time tomorrow evening to post a blog with the solution(s).P.s @ZoharPeled you can always contact me in private on Facebook. No need to wait that I will come here why mistake :-)

    – Ronen Ariely
    Mar 24 at 22:31















0














This is a classing gaps-and-islands problem.
The key here is how to identify the groups.



If the difference between tFrom and tUntil is always exactly one hour, you can ignore the tUntil and work only based on the differences between tFrom of different records.

Use a common table expression to identify the groups, and then select min(tFrom) and max(tUntil) from it, grouped by id and group.



What you do is calculate the hours difference between the tFrom and some fixed date, and you subtract that value from row_number ordered by tFrom (and partitioned by id in this case).



This means that consecutive values of tFrom will get the same group key (consecutive here means by the hour in this case):



WITH CTE AS
(
SELECT ID,
tFrom,
tUntil,
ROW_NUMBER() OVER(PARTITION BY id ORDER BY tFrom) -
DATEDIFF(HOUR, '2019-01-01', tFrom) As grp
FROM @Test
)

SELECT ID,
MIN(tFrom) As tFrom,
MAX(tUntil) As tUntil
FROM CTE
GROUP BY ID, grp
ORDER BY Id, tFrom


If the difference between tFrom and tUntill is not fixed, than it's going to be more cumbersome to identify the groups.

I came up with a solution involving three common table expressions - the first is to get the datediff between the current row's tUntill and the next row's tFrom, then calculate a group divider based on previous row's difference, and then calculate the group id based on sums of the dividers:



WITH CTE1 AS
(
SELECT ID,
tFrom,
tUntil,
DATEDIFF(HOUR, tUntil, LEAD(tFrom) OVER(PARTITION BY id ORDER BY tFrom)) As DiffNext
FROM @Test
), CTE2 AS
(
SELECT ID,
tFrom,
tUntil,
ISNULL(SIGN(LAG(DiffNext) OVER(PARTITION BY id ORDER BY tFrom)), 1) AS GroupDivider
FROM CTE1
), CTE3 AS
(
SELECT ID,
tFrom,
tUntil,
SUM(GroupDivider) OVER(PARTITION BY id ORDER BY tFrom) As GroupId
FROM CTE2
)

SELECT ID,
MIN(tFrom) As tFrom,
MAX(tUntil) As tUntil
FROM CTE3
GROUP BY ID, GroupId
ORDER BY ID, tFrom





share|improve this answer

























  • Dear Zohar, thanks a lot! This is working perfectly. As I am not so experienced with this stuff I will try to understand what you did here. Magic :-).

    – tommired
    Mar 22 at 11:06











  • If you need a clarification simply ask... Glad to help :-)

    – Zohar Peled
    Mar 22 at 11:18











  • Hi @ZoharPeled, this solution will not work if you have overlap in the ranges of the time. For example try to add another row insert into TEST Values (1,'2019-1-1 10:00', '2019-1-1 23:00') ,and now you supposed to get only one row in the result set for ID = 1 but you still get three rows

    – Ronen Ariely
    Mar 22 at 13:19






  • 1





    @RonenAriely I've seen Alan around here. we've occasionally posted answers to same questions, but I don't remember getting downvotes on these question. My point is that the downvote could have been from anyone with high enough reputation (IIRC 125) - but I don't think it was from Alan. He does seem to have a tendency for self promoting, but not at the expense of other SO members. I used to get pissed anytime one of my answers was downvoted but I've realized that even when I know I'm correct, some people will still think I'm wrong, and there's nothing I can do about it [to be continued...]

    – Zohar Peled
    Mar 24 at 5:50






  • 1





    Hi @ZoharPeled, for you anything :-). I will provide a full solution(s) - there are several options, the common option which is using the "Gaps and Islands" logic,which I mentioned before, and there is my secrete solution which was not yet publish in blog but I did mentioned it several times in lectures and in forums... It is 00:30 AM now and I go to sleep. I hope to have time tomorrow evening to post a blog with the solution(s).P.s @ZoharPeled you can always contact me in private on Facebook. No need to wait that I will come here why mistake :-)

    – Ronen Ariely
    Mar 24 at 22:31













0












0








0







This is a classing gaps-and-islands problem.
The key here is how to identify the groups.



If the difference between tFrom and tUntil is always exactly one hour, you can ignore the tUntil and work only based on the differences between tFrom of different records.

Use a common table expression to identify the groups, and then select min(tFrom) and max(tUntil) from it, grouped by id and group.



What you do is calculate the hours difference between the tFrom and some fixed date, and you subtract that value from row_number ordered by tFrom (and partitioned by id in this case).



This means that consecutive values of tFrom will get the same group key (consecutive here means by the hour in this case):



WITH CTE AS
(
SELECT ID,
tFrom,
tUntil,
ROW_NUMBER() OVER(PARTITION BY id ORDER BY tFrom) -
DATEDIFF(HOUR, '2019-01-01', tFrom) As grp
FROM @Test
)

SELECT ID,
MIN(tFrom) As tFrom,
MAX(tUntil) As tUntil
FROM CTE
GROUP BY ID, grp
ORDER BY Id, tFrom


If the difference between tFrom and tUntill is not fixed, than it's going to be more cumbersome to identify the groups.

I came up with a solution involving three common table expressions - the first is to get the datediff between the current row's tUntill and the next row's tFrom, then calculate a group divider based on previous row's difference, and then calculate the group id based on sums of the dividers:



WITH CTE1 AS
(
SELECT ID,
tFrom,
tUntil,
DATEDIFF(HOUR, tUntil, LEAD(tFrom) OVER(PARTITION BY id ORDER BY tFrom)) As DiffNext
FROM @Test
), CTE2 AS
(
SELECT ID,
tFrom,
tUntil,
ISNULL(SIGN(LAG(DiffNext) OVER(PARTITION BY id ORDER BY tFrom)), 1) AS GroupDivider
FROM CTE1
), CTE3 AS
(
SELECT ID,
tFrom,
tUntil,
SUM(GroupDivider) OVER(PARTITION BY id ORDER BY tFrom) As GroupId
FROM CTE2
)

SELECT ID,
MIN(tFrom) As tFrom,
MAX(tUntil) As tUntil
FROM CTE3
GROUP BY ID, GroupId
ORDER BY ID, tFrom





share|improve this answer















This is a classing gaps-and-islands problem.
The key here is how to identify the groups.



If the difference between tFrom and tUntil is always exactly one hour, you can ignore the tUntil and work only based on the differences between tFrom of different records.

Use a common table expression to identify the groups, and then select min(tFrom) and max(tUntil) from it, grouped by id and group.



What you do is calculate the hours difference between the tFrom and some fixed date, and you subtract that value from row_number ordered by tFrom (and partitioned by id in this case).



This means that consecutive values of tFrom will get the same group key (consecutive here means by the hour in this case):



WITH CTE AS
(
SELECT ID,
tFrom,
tUntil,
ROW_NUMBER() OVER(PARTITION BY id ORDER BY tFrom) -
DATEDIFF(HOUR, '2019-01-01', tFrom) As grp
FROM @Test
)

SELECT ID,
MIN(tFrom) As tFrom,
MAX(tUntil) As tUntil
FROM CTE
GROUP BY ID, grp
ORDER BY Id, tFrom


If the difference between tFrom and tUntill is not fixed, than it's going to be more cumbersome to identify the groups.

I came up with a solution involving three common table expressions - the first is to get the datediff between the current row's tUntill and the next row's tFrom, then calculate a group divider based on previous row's difference, and then calculate the group id based on sums of the dividers:



WITH CTE1 AS
(
SELECT ID,
tFrom,
tUntil,
DATEDIFF(HOUR, tUntil, LEAD(tFrom) OVER(PARTITION BY id ORDER BY tFrom)) As DiffNext
FROM @Test
), CTE2 AS
(
SELECT ID,
tFrom,
tUntil,
ISNULL(SIGN(LAG(DiffNext) OVER(PARTITION BY id ORDER BY tFrom)), 1) AS GroupDivider
FROM CTE1
), CTE3 AS
(
SELECT ID,
tFrom,
tUntil,
SUM(GroupDivider) OVER(PARTITION BY id ORDER BY tFrom) As GroupId
FROM CTE2
)

SELECT ID,
MIN(tFrom) As tFrom,
MAX(tUntil) As tUntil
FROM CTE3
GROUP BY ID, GroupId
ORDER BY ID, tFrom






share|improve this answer














share|improve this answer



share|improve this answer








edited Mar 22 at 9:54

























answered Mar 22 at 8:47









Zohar PeledZohar Peled

57.1k73475




57.1k73475












  • Dear Zohar, thanks a lot! This is working perfectly. As I am not so experienced with this stuff I will try to understand what you did here. Magic :-).

    – tommired
    Mar 22 at 11:06











  • If you need a clarification simply ask... Glad to help :-)

    – Zohar Peled
    Mar 22 at 11:18











  • Hi @ZoharPeled, this solution will not work if you have overlap in the ranges of the time. For example try to add another row insert into TEST Values (1,'2019-1-1 10:00', '2019-1-1 23:00') ,and now you supposed to get only one row in the result set for ID = 1 but you still get three rows

    – Ronen Ariely
    Mar 22 at 13:19






  • 1





    @RonenAriely I've seen Alan around here. we've occasionally posted answers to same questions, but I don't remember getting downvotes on these question. My point is that the downvote could have been from anyone with high enough reputation (IIRC 125) - but I don't think it was from Alan. He does seem to have a tendency for self promoting, but not at the expense of other SO members. I used to get pissed anytime one of my answers was downvoted but I've realized that even when I know I'm correct, some people will still think I'm wrong, and there's nothing I can do about it [to be continued...]

    – Zohar Peled
    Mar 24 at 5:50






  • 1





    Hi @ZoharPeled, for you anything :-). I will provide a full solution(s) - there are several options, the common option which is using the "Gaps and Islands" logic,which I mentioned before, and there is my secrete solution which was not yet publish in blog but I did mentioned it several times in lectures and in forums... It is 00:30 AM now and I go to sleep. I hope to have time tomorrow evening to post a blog with the solution(s).P.s @ZoharPeled you can always contact me in private on Facebook. No need to wait that I will come here why mistake :-)

    – Ronen Ariely
    Mar 24 at 22:31

















  • Dear Zohar, thanks a lot! This is working perfectly. As I am not so experienced with this stuff I will try to understand what you did here. Magic :-).

    – tommired
    Mar 22 at 11:06











  • If you need a clarification simply ask... Glad to help :-)

    – Zohar Peled
    Mar 22 at 11:18











  • Hi @ZoharPeled, this solution will not work if you have overlap in the ranges of the time. For example try to add another row insert into TEST Values (1,'2019-1-1 10:00', '2019-1-1 23:00') ,and now you supposed to get only one row in the result set for ID = 1 but you still get three rows

    – Ronen Ariely
    Mar 22 at 13:19






  • 1





    @RonenAriely I've seen Alan around here. we've occasionally posted answers to same questions, but I don't remember getting downvotes on these question. My point is that the downvote could have been from anyone with high enough reputation (IIRC 125) - but I don't think it was from Alan. He does seem to have a tendency for self promoting, but not at the expense of other SO members. I used to get pissed anytime one of my answers was downvoted but I've realized that even when I know I'm correct, some people will still think I'm wrong, and there's nothing I can do about it [to be continued...]

    – Zohar Peled
    Mar 24 at 5:50






  • 1





    Hi @ZoharPeled, for you anything :-). I will provide a full solution(s) - there are several options, the common option which is using the "Gaps and Islands" logic,which I mentioned before, and there is my secrete solution which was not yet publish in blog but I did mentioned it several times in lectures and in forums... It is 00:30 AM now and I go to sleep. I hope to have time tomorrow evening to post a blog with the solution(s).P.s @ZoharPeled you can always contact me in private on Facebook. No need to wait that I will come here why mistake :-)

    – Ronen Ariely
    Mar 24 at 22:31
















Dear Zohar, thanks a lot! This is working perfectly. As I am not so experienced with this stuff I will try to understand what you did here. Magic :-).

– tommired
Mar 22 at 11:06





Dear Zohar, thanks a lot! This is working perfectly. As I am not so experienced with this stuff I will try to understand what you did here. Magic :-).

– tommired
Mar 22 at 11:06













If you need a clarification simply ask... Glad to help :-)

– Zohar Peled
Mar 22 at 11:18





If you need a clarification simply ask... Glad to help :-)

– Zohar Peled
Mar 22 at 11:18













Hi @ZoharPeled, this solution will not work if you have overlap in the ranges of the time. For example try to add another row insert into TEST Values (1,'2019-1-1 10:00', '2019-1-1 23:00') ,and now you supposed to get only one row in the result set for ID = 1 but you still get three rows

– Ronen Ariely
Mar 22 at 13:19





Hi @ZoharPeled, this solution will not work if you have overlap in the ranges of the time. For example try to add another row insert into TEST Values (1,'2019-1-1 10:00', '2019-1-1 23:00') ,and now you supposed to get only one row in the result set for ID = 1 but you still get three rows

– Ronen Ariely
Mar 22 at 13:19




1




1





@RonenAriely I've seen Alan around here. we've occasionally posted answers to same questions, but I don't remember getting downvotes on these question. My point is that the downvote could have been from anyone with high enough reputation (IIRC 125) - but I don't think it was from Alan. He does seem to have a tendency for self promoting, but not at the expense of other SO members. I used to get pissed anytime one of my answers was downvoted but I've realized that even when I know I'm correct, some people will still think I'm wrong, and there's nothing I can do about it [to be continued...]

– Zohar Peled
Mar 24 at 5:50





@RonenAriely I've seen Alan around here. we've occasionally posted answers to same questions, but I don't remember getting downvotes on these question. My point is that the downvote could have been from anyone with high enough reputation (IIRC 125) - but I don't think it was from Alan. He does seem to have a tendency for self promoting, but not at the expense of other SO members. I used to get pissed anytime one of my answers was downvoted but I've realized that even when I know I'm correct, some people will still think I'm wrong, and there's nothing I can do about it [to be continued...]

– Zohar Peled
Mar 24 at 5:50




1




1





Hi @ZoharPeled, for you anything :-). I will provide a full solution(s) - there are several options, the common option which is using the "Gaps and Islands" logic,which I mentioned before, and there is my secrete solution which was not yet publish in blog but I did mentioned it several times in lectures and in forums... It is 00:30 AM now and I go to sleep. I hope to have time tomorrow evening to post a blog with the solution(s).P.s @ZoharPeled you can always contact me in private on Facebook. No need to wait that I will come here why mistake :-)

– Ronen Ariely
Mar 24 at 22:31





Hi @ZoharPeled, for you anything :-). I will provide a full solution(s) - there are several options, the common option which is using the "Gaps and Islands" logic,which I mentioned before, and there is my secrete solution which was not yet publish in blog but I did mentioned it several times in lectures and in forums... It is 00:30 AM now and I go to sleep. I hope to have time tomorrow evening to post a blog with the solution(s).P.s @ZoharPeled you can always contact me in private on Facebook. No need to wait that I will come here why mistake :-)

– Ronen Ariely
Mar 24 at 22:31













0














Good day,



In order to have a flexible solution which cover overlap in the ranges of the time, there are several solutions which we can use. "Gaps & Islands" approach is not the best (from the performance point of view), but it will work, and there are worse options as well (like using loop/cursor). Since "Gaps & Islands" was the phrase that mentioned in the comments and in the solution which was discuss in the comments, l will first show this solution in short.



The solution using the "Gaps & Islands" approach is based on two steps (one query which use CTE). First, you split the ranges into "points in time". Next using "numbers" table or better in this case a "Times" table, you can get the final result SET by finding the gaps between the points, which is classic "Gaps & Islands" problem.



I HIGHLY recommend to follow the post, which I published, and follow it from start to end! There are limitations and disadvantages for this approach, which you must understand. Moreover, the post present the "way of thinking" and how we solve problems like this one step-by-step.



In the post I start with the simplest case of ranges of integers, for example 2-4, 6-8, 8-10, 13-14 which should be grouped into 2-4, 6-10, 13-14.



Next I move to explain issue related to the resolution of space between the ranges, and I present a solution for Ranges of Decimal numbers, which cover the issue.



Finally, using the solution which I presented in detail for INTEGERS, I presented a solution for "Grouping continuous time-slots together", which was the original question in the forum.



Note! The solution which presented here is probably the one which I recommend to use in production. In my next post I published a totally different approach using my personal trick, which can improve performance dramatically.



In short, for the sake of the discussion I will create a Times table (you can use Numbers table directly if you really want). Notice that I create the Times table using a Numbers table.



DROP TABLE IF EXISTS Times
GO
SELECT DT = DATEADD(MINUTE, N*10, '2010-01-01')
INTO Times
FROM Numbers
GO
CREATE CLUSTERED INDEX IX_DT ON Times(DT)
GO
SELECT TOP 1000 DT from Times
GO


and using this table we can solve the issue



;With MyCTE01 as (
SELECT DISTINCT ID, DT
FROM TEST t
INNER JOIN Times dt ON DT between tFrom and tUntil
)
,MyCTE02 as(
SELECT ID, DT,
MyGroup =
DATEDIFF(MINUTE,
DATEADD(MINUTE, 10 * ROW_NUMBER()OVER(PARTITION BY ID ORDER BY ID,DT),0),
DT
)
from MyCTE01
--order by ID,DT
)
SELECT ID, MIN(DT) tFrom, MAX(DT) tUntil
FROM MyCTE02
GROUP BY ID, MyGroup
ORDER BY ID, tFrom
GO


Note! I highly recommend to check the second post (Part 2) before choosing the solution that fit you in production.



I hope that this cover the discussion and that it was helpful






share|improve this answer

























  • Hi @ZoharPeled, you are welcome to check the solutions (i published here the "Gaps & Islands" approach as requested, and I published a post about another approach.

    – Ronen Ariely
    Apr 3 at 13:18











  • Hi @tommired, please inform me if something is not clear. I will be happy to elaborate more :-)

    – Ronen Ariely
    Apr 3 at 13:19















0














Good day,



In order to have a flexible solution which cover overlap in the ranges of the time, there are several solutions which we can use. "Gaps & Islands" approach is not the best (from the performance point of view), but it will work, and there are worse options as well (like using loop/cursor). Since "Gaps & Islands" was the phrase that mentioned in the comments and in the solution which was discuss in the comments, l will first show this solution in short.



The solution using the "Gaps & Islands" approach is based on two steps (one query which use CTE). First, you split the ranges into "points in time". Next using "numbers" table or better in this case a "Times" table, you can get the final result SET by finding the gaps between the points, which is classic "Gaps & Islands" problem.



I HIGHLY recommend to follow the post, which I published, and follow it from start to end! There are limitations and disadvantages for this approach, which you must understand. Moreover, the post present the "way of thinking" and how we solve problems like this one step-by-step.



In the post I start with the simplest case of ranges of integers, for example 2-4, 6-8, 8-10, 13-14 which should be grouped into 2-4, 6-10, 13-14.



Next I move to explain issue related to the resolution of space between the ranges, and I present a solution for Ranges of Decimal numbers, which cover the issue.



Finally, using the solution which I presented in detail for INTEGERS, I presented a solution for "Grouping continuous time-slots together", which was the original question in the forum.



Note! The solution which presented here is probably the one which I recommend to use in production. In my next post I published a totally different approach using my personal trick, which can improve performance dramatically.



In short, for the sake of the discussion I will create a Times table (you can use Numbers table directly if you really want). Notice that I create the Times table using a Numbers table.



DROP TABLE IF EXISTS Times
GO
SELECT DT = DATEADD(MINUTE, N*10, '2010-01-01')
INTO Times
FROM Numbers
GO
CREATE CLUSTERED INDEX IX_DT ON Times(DT)
GO
SELECT TOP 1000 DT from Times
GO


and using this table we can solve the issue



;With MyCTE01 as (
SELECT DISTINCT ID, DT
FROM TEST t
INNER JOIN Times dt ON DT between tFrom and tUntil
)
,MyCTE02 as(
SELECT ID, DT,
MyGroup =
DATEDIFF(MINUTE,
DATEADD(MINUTE, 10 * ROW_NUMBER()OVER(PARTITION BY ID ORDER BY ID,DT),0),
DT
)
from MyCTE01
--order by ID,DT
)
SELECT ID, MIN(DT) tFrom, MAX(DT) tUntil
FROM MyCTE02
GROUP BY ID, MyGroup
ORDER BY ID, tFrom
GO


Note! I highly recommend to check the second post (Part 2) before choosing the solution that fit you in production.



I hope that this cover the discussion and that it was helpful






share|improve this answer

























  • Hi @ZoharPeled, you are welcome to check the solutions (i published here the "Gaps & Islands" approach as requested, and I published a post about another approach.

    – Ronen Ariely
    Apr 3 at 13:18











  • Hi @tommired, please inform me if something is not clear. I will be happy to elaborate more :-)

    – Ronen Ariely
    Apr 3 at 13:19













0












0








0







Good day,



In order to have a flexible solution which cover overlap in the ranges of the time, there are several solutions which we can use. "Gaps & Islands" approach is not the best (from the performance point of view), but it will work, and there are worse options as well (like using loop/cursor). Since "Gaps & Islands" was the phrase that mentioned in the comments and in the solution which was discuss in the comments, l will first show this solution in short.



The solution using the "Gaps & Islands" approach is based on two steps (one query which use CTE). First, you split the ranges into "points in time". Next using "numbers" table or better in this case a "Times" table, you can get the final result SET by finding the gaps between the points, which is classic "Gaps & Islands" problem.



I HIGHLY recommend to follow the post, which I published, and follow it from start to end! There are limitations and disadvantages for this approach, which you must understand. Moreover, the post present the "way of thinking" and how we solve problems like this one step-by-step.



In the post I start with the simplest case of ranges of integers, for example 2-4, 6-8, 8-10, 13-14 which should be grouped into 2-4, 6-10, 13-14.



Next I move to explain issue related to the resolution of space between the ranges, and I present a solution for Ranges of Decimal numbers, which cover the issue.



Finally, using the solution which I presented in detail for INTEGERS, I presented a solution for "Grouping continuous time-slots together", which was the original question in the forum.



Note! The solution which presented here is probably the one which I recommend to use in production. In my next post I published a totally different approach using my personal trick, which can improve performance dramatically.



In short, for the sake of the discussion I will create a Times table (you can use Numbers table directly if you really want). Notice that I create the Times table using a Numbers table.



DROP TABLE IF EXISTS Times
GO
SELECT DT = DATEADD(MINUTE, N*10, '2010-01-01')
INTO Times
FROM Numbers
GO
CREATE CLUSTERED INDEX IX_DT ON Times(DT)
GO
SELECT TOP 1000 DT from Times
GO


and using this table we can solve the issue



;With MyCTE01 as (
SELECT DISTINCT ID, DT
FROM TEST t
INNER JOIN Times dt ON DT between tFrom and tUntil
)
,MyCTE02 as(
SELECT ID, DT,
MyGroup =
DATEDIFF(MINUTE,
DATEADD(MINUTE, 10 * ROW_NUMBER()OVER(PARTITION BY ID ORDER BY ID,DT),0),
DT
)
from MyCTE01
--order by ID,DT
)
SELECT ID, MIN(DT) tFrom, MAX(DT) tUntil
FROM MyCTE02
GROUP BY ID, MyGroup
ORDER BY ID, tFrom
GO


Note! I highly recommend to check the second post (Part 2) before choosing the solution that fit you in production.



I hope that this cover the discussion and that it was helpful






share|improve this answer















Good day,



In order to have a flexible solution which cover overlap in the ranges of the time, there are several solutions which we can use. "Gaps & Islands" approach is not the best (from the performance point of view), but it will work, and there are worse options as well (like using loop/cursor). Since "Gaps & Islands" was the phrase that mentioned in the comments and in the solution which was discuss in the comments, l will first show this solution in short.



The solution using the "Gaps & Islands" approach is based on two steps (one query which use CTE). First, you split the ranges into "points in time". Next using "numbers" table or better in this case a "Times" table, you can get the final result SET by finding the gaps between the points, which is classic "Gaps & Islands" problem.



I HIGHLY recommend to follow the post, which I published, and follow it from start to end! There are limitations and disadvantages for this approach, which you must understand. Moreover, the post present the "way of thinking" and how we solve problems like this one step-by-step.



In the post I start with the simplest case of ranges of integers, for example 2-4, 6-8, 8-10, 13-14 which should be grouped into 2-4, 6-10, 13-14.



Next I move to explain issue related to the resolution of space between the ranges, and I present a solution for Ranges of Decimal numbers, which cover the issue.



Finally, using the solution which I presented in detail for INTEGERS, I presented a solution for "Grouping continuous time-slots together", which was the original question in the forum.



Note! The solution which presented here is probably the one which I recommend to use in production. In my next post I published a totally different approach using my personal trick, which can improve performance dramatically.



In short, for the sake of the discussion I will create a Times table (you can use Numbers table directly if you really want). Notice that I create the Times table using a Numbers table.



DROP TABLE IF EXISTS Times
GO
SELECT DT = DATEADD(MINUTE, N*10, '2010-01-01')
INTO Times
FROM Numbers
GO
CREATE CLUSTERED INDEX IX_DT ON Times(DT)
GO
SELECT TOP 1000 DT from Times
GO


and using this table we can solve the issue



;With MyCTE01 as (
SELECT DISTINCT ID, DT
FROM TEST t
INNER JOIN Times dt ON DT between tFrom and tUntil
)
,MyCTE02 as(
SELECT ID, DT,
MyGroup =
DATEDIFF(MINUTE,
DATEADD(MINUTE, 10 * ROW_NUMBER()OVER(PARTITION BY ID ORDER BY ID,DT),0),
DT
)
from MyCTE01
--order by ID,DT
)
SELECT ID, MIN(DT) tFrom, MAX(DT) tUntil
FROM MyCTE02
GROUP BY ID, MyGroup
ORDER BY ID, tFrom
GO


Note! I highly recommend to check the second post (Part 2) before choosing the solution that fit you in production.



I hope that this cover the discussion and that it was helpful







share|improve this answer














share|improve this answer



share|improve this answer








edited Apr 3 at 13:01

























answered Mar 25 at 18:10









Ronen ArielyRonen Ariely

1,111413




1,111413












  • Hi @ZoharPeled, you are welcome to check the solutions (i published here the "Gaps & Islands" approach as requested, and I published a post about another approach.

    – Ronen Ariely
    Apr 3 at 13:18











  • Hi @tommired, please inform me if something is not clear. I will be happy to elaborate more :-)

    – Ronen Ariely
    Apr 3 at 13:19

















  • Hi @ZoharPeled, you are welcome to check the solutions (i published here the "Gaps & Islands" approach as requested, and I published a post about another approach.

    – Ronen Ariely
    Apr 3 at 13:18











  • Hi @tommired, please inform me if something is not clear. I will be happy to elaborate more :-)

    – Ronen Ariely
    Apr 3 at 13:19
















Hi @ZoharPeled, you are welcome to check the solutions (i published here the "Gaps & Islands" approach as requested, and I published a post about another approach.

– Ronen Ariely
Apr 3 at 13:18





Hi @ZoharPeled, you are welcome to check the solutions (i published here the "Gaps & Islands" approach as requested, and I published a post about another approach.

– Ronen Ariely
Apr 3 at 13:18













Hi @tommired, please inform me if something is not clear. I will be happy to elaborate more :-)

– Ronen Ariely
Apr 3 at 13:19





Hi @tommired, please inform me if something is not clear. I will be happy to elaborate more :-)

– Ronen Ariely
Apr 3 at 13:19

















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55294707%2ftsql-grouping-continuous-timeslots-together%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

SQL error code 1064 with creating Laravel foreign keysForeign key constraints: When to use ON UPDATE and ON DELETEDropping column with foreign key Laravel error: General error: 1025 Error on renameLaravel SQL Can't create tableLaravel Migration foreign key errorLaravel php artisan migrate:refresh giving a syntax errorSQLSTATE[42S01]: Base table or view already exists or Base table or view already exists: 1050 Tableerror in migrating laravel file to xampp serverSyntax error or access violation: 1064:syntax to use near 'unsigned not null, modelName varchar(191) not null, title varchar(191) not nLaravel cannot create new table field in mysqlLaravel 5.7:Last migration creates table but is not registered in the migration table

용인 삼성생명 블루밍스 목차 통계 역대 감독 선수단 응원단 경기장 같이 보기 외부 링크 둘러보기 메뉴samsungblueminx.comeh선수 명단용인 삼성생명 블루밍스용인 삼성생명 블루밍스ehsamsungblueminx.comeheheheh

155 수학 과학 기타 둘러보기 메뉴eh추가해eh문서를 완성해