Reputation: 152
The record exists in this format:
+-----------------------------+-----------------------------+----------+------------+----------+-----------------+
| StartDTM | EndDTM | PersonID | PersonName | Duration | TimeSheetItemID |
+-----------------------------+-----------------------------+----------+------------+----------+-----------------+
| 2019-08-17 17:48:00.0000000 | 2019-08-17 18:00:00.0000000 | 111111 | Smith, Bob | 0.200000 | 154446149 |
+-----------------------------+-----------------------------+----------+------------+----------+-----------------+
| 2019-08-17 18:00:00.0000000 | 2019-08-17 23:00:00.0000000 | 111111 | Smith, Bob | 5.000000 | 154446149 |
+-----------------------------+-----------------------------+----------+------------+----------+-----------------+
| 2019-08-17 23:00:00.0000000 | 2019-08-17 23:30:00.0000000 | 111111 | Smith, Bob | 0.500000 | 154446149 |
+-----------------------------+-----------------------------+----------+------------+----------+-----------------+
| 2019-08-17 23:30:00.0000000 | 2019-08-18 00:00:00.0000000 | 111111 | Smith, Bob | 0.500000 | 154446149 |
+-----------------------------+-----------------------------+----------+------------+----------+-----------------+
| 2019-08-18 00:00:00.0000000 | 2019-08-18 02:14:00.0000000 | 111111 | Smith, Bob | 2.233333 | 154446149 |
+-----------------------------+-----------------------------+----------+------------+----------+-----------------+
| 2019-08-18 02:14:00.0000000 | 2019-08-18 06:18:00.0000000 | 111111 | Smith, Bob | 4.066666 | 154478804 |
+-----------------------------+-----------------------------+----------+------------+----------+-----------------+
| 2019-08-25 17:48:00.0000000 | 2019-08-25 18:00:00.0000000 | 111111 | Smith, Bob | 0.200000 | 154745867 |
+-----------------------------+-----------------------------+----------+------------+----------+-----------------+
| 2019-08-25 18:00:00.0000000 | 2019-08-25 23:00:00.0000000 | 111111 | Smith, Bob | 5.000000 | 154745867 |
+-----------------------------+-----------------------------+----------+------------+----------+-----------------+
| 2019-08-25 23:00:00.0000000 | 2019-08-25 23:30:00.0000000 | 111111 | Smith, Bob | 0.500000 | 154745867 |
+-----------------------------+-----------------------------+----------+------------+----------+-----------------+
| 2019-08-25 23:30:00.0000000 | 2019-08-26 00:00:00.0000000 | 111111 | Smith, Bob | 0.500000 | 154745867 |
+-----------------------------+-----------------------------+----------+------------+----------+-----------------+
| 2019-08-26 00:00:00.0000000 | 2019-08-26 02:00:00.0000000 | 111111 | Smith, Bob | 2.000000 | 154745867 |
+-----------------------------+-----------------------------+----------+------------+----------+-----------------+
| 2019-08-26 02:00:00.0000000 | 2019-08-26 05:54:00.0000000 | 111111 | Smith, Bob | 3.900000 | 154756492 |
+-----------------------------+-----------------------------+----------+------------+----------+-----------------+
I need to select the MIN StartDTM and the MAX EndDTM within a 24 hour period. I have tried selecting MIN(StartDTM) and MAX(EndDTM) in combination with GROUP BY PersonName and TimeSheetID, but this fails as sometimes more than one TimeSheetID exists within a 24 hour period (See row 6 above).
My desired results should look like this:
+-----------------------------+-----------------------------+----------+------------+-----------------+
| StartDTM | EndDTM | PersonID | PersonName | TimeSheetItemID |
+-----------------------------+-----------------------------+----------+------------+-----------------+
| 2019-08-17 17:48:00.0000000 | 2019-08-18 06:18:00.0000000 | 111111 | Smith, Bob | 154446149 |
+-----------------------------+-----------------------------+----------+------------+-----------------+
| 2019-08-25 17:48:00.0000000 | 2019-08-26 05:54:00.0000000 | 111111 | Smith, Bob | 154745867 |
+-----------------------------+-----------------------------+----------+------------+-----------------+
Is this possible to achieve in T-SQL?
Upvotes: 0
Views: 308
Reputation: 13959
You can use lead and lag as below to solve this problem:
;with cte_bucket as (
select *, sum(difsec) over(partition by personid order by startdtm) bucket from (
select *, coalesce(ABS(datediff(ss, startdtm, lag(enddtm) over( partition by personid order by startdtm))), 1) difsec
from #table
) a
)
select min(startdtm), max(enddtm), personid, personname, min(timesheetitemid) from cte_bucket
group by personid, personname, bucket
Code for reference:
https://rextester.com/UNF89433
+----+---------------------+---------------------+----------+------------+-----------------+ | | startDTM | endDTM | personid | personname | TimesheetItemId | +----+---------------------+---------------------+----------+------------+-----------------+ | 1 | 17.08.2019 17:48:00 | 18.08.2019 06:18:00 | 111111 | Smith, Bob | 154446149 | | 2 | 25.08.2019 17:48:00 | 26.08.2019 05:54:00 | 111111 | Smith, Bob | 154745867 | +----+---------------------+---------------------+----------+------------+-----------------+
Upvotes: 0
Reputation: 2135
If I understand that you want min/max per day, then you need to also group by the day. untested
select StartDTM, EndDTM, startTable.PersonID
,startTable.PersonName, startTable.TimeSheetItemID
from (
select min(StartDTM) StartDTM, PersonID, PersonName, TimeSheetItemID
from YourTable
group by convert(date,StartDTM), PersonID, TimeSheetItemID, PersonName
) startTable
full outer join (
select max(EndDTM) EndDTM, PersonID, TimeSheetItemID
from YourTable
group by convert(date,endDTM), PersonID, TimeSheetItemID
) EndTable
on startTable.PersonID = endTable.PersonID
and startTable.TimeSheetItemID = endTable.TimeSheetItemID
where convert(date,StartDTM) = convert(date,EndDTM)
order by startTable.PersonID,StartDTM
Timesheets that do not have both a startDTM and endDTM in a given day should have null values in this query.
If you are interested in any 24 hour period then that's a whole different thing.
Upvotes: 0
Reputation: 1269493
This is gaps-and-islands problem. You need to find where the islands start. In this case, I recommend a cumulative maximum.
select personId, min(startTM), max(endTM)
from (select t.*,
sum(case when prev_maxEndTm >= dateadd(day, -1, startTm)
then 0 -- maximum is later than this record so no new island
else 1 -- maximum is earlier so new island
end) over (partition by personId order by startTm) as grp
from (select t.*,
max(EndTm) over (partition by personId
order by startTm
rows between unbounded preceding and 1 preceding
) as prev_maxEndTm
from t
) t
) t
group by personId;
Upvotes: 1