Problem in formatting result set in desired format - sql

I have devices which are installed in a different location with different area ID I am returning the device activity status of different areas on an hourly basis in the following format.
AreaId | UpdatedOn | DeviceStatus
1 | 2018-08-08 00:00:00.000 | Active
1 | 2018-08-08 01:00:00.000 | Active
1 | 2018-08-08 02:00:00.000 | Active
2 | 2018-08-08 00:00:00.000 | Inactive
2 | 2018-08-08 01:00:00.000 | Active
2 | 2018-08-08 02:00:00.000 | Active
3 | 2018-08-08 00:00:00.000 | Active
3 | 2018-08-08 01:00:00.000 | Inactive
3 | 2018-08-08 02:00:00.000 | Inactive
As its clearly visible that Device 1 was active throughout. Device 2 was not active from 00.00 to 01.00 Hrs
and device 3 was not active from 01.00 to 02.00 and 02.00 to 03.00 Hrs.
I want to show this data in the following format.
Status of devices for 8 August 2018 0:00 Hrs to 03:00 Hrs
Areaid | Status
1 | Active
2 | Not Active between 00:00 hrs to 01:00 hrs
3 | Not Active between 01:00 hrs to 02:00 hrs and 02:00 hrs to 03:00 hrs
for all the Areas.
How can I achieve this?

You can try to use STUFF function in subquery to get DeviceStatus = 'Inactive' row data, then outer join base on AreaId table
SELECT t2.AreaId, coalesce(Status,'Active') Status
FROM (
SELECT distinct AreaId,DeviceStatus,
STUFF((
SELECT ' and ' + CONVERT(VARCHAR(5),UpdatedOn,108) + ' hrs' + ' to ' + CONVERT(VARCHAR(5),DATEADD(HOUR,1,UpdatedOn),108) + ' hrs'
FROM T tt
WHERE tt.AreaId = t1.AreaId and tt.DeviceStatus = t1.DeviceStatus
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,4,'') Status
FROM T t1
WHERE DeviceStatus = 'Inactive'
) t1 RIGHT JOIN
(
SELECT distinct AreaId
FROM T
) t2
on t1.AreaId = t2.AreaId
sqlfiddle
Result
AreaId Status
1 Active
2 00:00 hrs to 01:00 hrs
3 01:00 hrs to 02:00 hrs and 02:00 hrs to 03:00 hrs

You can try below using lag() function
DEMO
select id,concat('Not Active between ', format(cast(prevd as datetime),' hh:mm '), 'hrs to ', format(cast(d as datetime),' hh:mm '), 'hrs') from
(select *,
LAG (d, 1, 0) OVER (PARTITION BY id ORDER BY d) prevd,
LAG (p, 1, 0) OVER (PARTITION BY id ORDER BY d) prevp
from cte1
)a where prevp<>'0' and p<>prevp
Output:
id status
1 Not Active between 01:00 hrs to 02:00 hrs
2 Not Active between 01:00 hrs to 02:00 hrs

Related

My SQL Query is working on one date, but I want start date to end date

I am using SQL Server 2005
I have two tables:
CheckInOut
TR BadgeNum USERID Dated Time CHECKTYPE
------- --------- ------ ----------------------- ----------------------- ----------
2337334 4 1 2018-04-01 00:00:00.000 2018-04-14 10:10:58.000 I
2337334 4 1 2018-04-01 00:00:00.000 2018-04-14 18:10:00.000 O
2337334 4 1 2018-04-02 00:00:00.000 2018-04-14 10:00:10.000 I
2337335 4 1 2018-04-02 00:00:00.000 2018-04-14 18:14:27.000 O
2337336 4 1 2018-04-03 00:00:00.000 2018-04-14 10:22:10.000 I
2337334 4 1 2018-04-03 00:00:00.000 2018-04-14 18:03:11.000 O
2337337 44 5 2018-04-01 00:00:00.000 2018-04-14 09:27:03.000 I
2337337 44 5 2018-04-01 00:00:00.000 2018-04-14 18:27:42.000 O
2337337 44 5 2018-04-02 00:00:00.000 2018-04-14 10:00:50.000 I
2337337 44 5 2018-04-02 00:00:00.000 2018-04-14 18:02:25.000 O
2337337 44 5 2018-04-03 00:00:00.000 2018-04-14 08:58:36.000 I
2337337 44 5 2018-04-03 00:00:00.000 2018-04-14 18:12:18.000 O
UserInfo
Tr UserID BadgeNumber Name
----- ------- ----------- --------------
13652 44 5 SAMIA NAZ
13653 4 1 Waqar Yousufzai
I need to calculate presence hours for each day for each user. My below query is working fine for given day. But I need to calculate for a given range. How do I get expected result?
Select isnull(max(ch.userid), 0)As 'ID'
,isnull(max(ch.badgenum), 0)as 'Badge#'
,isnull(max(convert(Char(10), ch.dated, 103)), '00:00')as 'Date'
,isnull(max(ui.name),'Empty')as 'Name'
,isnull(min(convert(VARCHAR(26), ch.time, 108)), '00:00') as 'Time In'
,case when min(ch.time) = max(ch.time) then '' else isnull(max(convert(VARCHAR(26), ch.time, 108)), '00:00') end as 'TimeOut'
,case when min(ch.time) = max(ch.time) then 'Absent' else 'Present' end as 'Status'
,isnull(CONVERT(varchar(3),DATEDIFF(minute,min(ch.time), max(ch.time))/60) + ' hrs and ' +
RIGHT('0' + CONVERT(varchar(2),DATEDIFF(minute,min(ch.time),max(ch.time))%60),2) + 'Min' , 0) as 'Total Hrs'
From CHECKINOUT ch left Join userinfo ui on ch.badgenum = ui.badgenumber
Where ch.Dated between '2018-04-01' and '2018-04-03' GROUP BY ch.badgenum
Query result
ID Badge# Date Name Time In TimeOut Status Total Hrs
--- ------ ---------- --------------- -------- ---------- -------- -----------------
4 1 03/04/2018 Waqar Yousufzai 11:33:34 18:24:23 Present 30 hrs and 14Min
82 3 03/04/2018 TANVEER ANSARI 09:37:14 19:18:22 Present 32 hrs and 37Min
13 4 03/04/2018 07:19:26 09:30:17 Present 21 hrs and 49Min
44 5 03/04/2018 SAMIA NAZ 08:53:15 18:25:21 Present 33 hrs and 24Min
28 7 03/04/2018 Anees Ahmad 08:34:57 22:00:38 Present 61 hrs and 25Min
46 8 03/04/2018 Shazia - OT 08:10:41 16:15:05 Present 32 hrs and 01Min
Expected result
ID Badge# Date Name Time In TimeOut Status Total Hrs
--- ------ ---------- --------------- -------- ---------- -------- -----------------
4 1 01/04/2018 Waqar Yousufzai 10:30:00 18:00:00 Present 7 hrs and 30Min
4 1 02/04/2018 Waqar Yousufzai 10:30:00 18:00:00 Present 7 hrs and 30Min
4 1 03/04/2018 Waqar Yousufzai 10:00:00 18:00:00 Present 8 hrs and 00Min
44 5 01/04/2018 SAMIA 08:00:00 18:00:00 Present 10 hrs and 00Min
44 5 02/04/2018 SAMIA 08:30:00 18:00:00 Present 9 hrs and 30Min
44 5 03/04/2018 SAMIA 08:00:00 18:00:00 Present 10 hrs and 00Min
You shouldn't do aggregation on date value, it must be part of grouping. Get time out and time in using conditional aggregation. And count total hours worked. Your query should be something like:
select
BadgeNum, USERID, Dated, Name
, right('0' + cast(datediff(mi, [in], [out]) / 60 as varchar(10)), 2) + ':'
+ right('0' + cast(datediff(mi, [in], [out]) % 60 as varchar(10)), 2)
from (
select
ch.BadgeNum, ch.USERID, dated = cast(ch.Dated as date), ui.Name
, [in] = min(case when ch.CHECKTYPE = 'I' then ch.Time end)
, [out] = min(case when ch.CHECKTYPE = 'O' then ch.Time end)
from
CheckInOut ch
left join UserInfo ui on ch.USERID = ui.badgenumber
where
ch.Dated >= '20180401'
and ch.Dated < '20180404'
group by ch.BadgeNum, ch.USERID, cast(ch.Dated as date), ui.Name
) t

Finding time between two dates on two different rows from two different columns

Hi I hope you guys can help, I have a few tables joined to get the right list of information I need. now I am stuck on one last thing.
I need to find the hours from the end date/time in one row and one column and the start date/time from a different row in a different column.
-------------------------------------------------
ID Name Startdate EndDate
-------------------------------------------------
1 BILL 2017-10-10 09:00 2017-10-10 19:00
1 BILL 2017-10-11 09:00 2017-10-11 19:00
1 BILL 2017-10-15 09:00 2017-10-15 15:00
1 BILL 2017-10-22 09:00 2017-10-22 11:00
2 TOM 2017-10-10 09:00 2017-10-10 14:00
2 TOM 2017-10-12 09:00 2017-10-12 16:00
3 SAM 2017-10-13 09:00 2017-10-13 20:00
3 SAM 2017-10-14 09:00 2017-10-14 19:00
-------------------------------------------------
--------------------------------------------------------------------
ID Name Startdate EndDate Hours Diff
--------------------------------------------------------------------
1 BILL 2017-10-10 09:00 2017-10-10 19:00 NULL
1 BILL 2017-10-11 09:00 2017-10-11 19:00 14
1 BILL 2017-10-15 09:00 2017-10-15 15:00 86
1 BILL 2017-10-22 09:00 2017-10-22 11:00 162
2 TOM 2017-10-10 09:00 2017-10-10 14:00 NULL
2 TOM 2017-10-12 09:00 2017-10-12 16:00 43
3 SAM 2017-10-13 09:00 2017-10-13 20:00 NULL
3 SAM 2017-10-14 09:00 2017-10-14 19:00 13
--------------------------------------------------------------------
SELECT
a.ID
,b.FirstName
,b.LastName
,c.StartTime
,c.EndTime
from
table1 as a
inner join table2 as b on a.idnumber = b.idnumber
left join table3 as c on a.idnumber = c.idnumber
where
((Select Count(idnumber) as expr1
From table1 as ab
where idnumber = a.idnumber))<=1)
Order by a.idnumber
Having it done in SQL would be good but also if it's simpler to do in SSRS in an expression instead of SQL as this is being put into a report that would be awesome.
Any help would be awesome, I'm sure it's simple just having issues.
Thanks.
For this simple case, you can use:
select id, name, startdate, enddate,
DATEDIFF(hh, (
select MAX(enddate)
from Table1 as T2
where T1.id = T2.id
and T1.startdate > T2.enddate ), startdate)
as [Hours Diff]
from table1 as T1
order by id, startdate
There is a working example here: http://sqlfiddle.com/#!6/95827/8
Are the rows that you are wanting to compare in order?
Row2 enddate vs Row1 startdate
Row3 enddate vs Row2 startdate
etc...
If this is the case you can use a "lag" function to bring in the values from a different row into the current row that is being compared.
I did something like this with Turophile's code:
select
id,
name,
startdate,
enddate,
datediff(hh,lag(startdate)over(partition by name order by startdate
asc),enddate)
from
table1 as T1
order by id, startdate
Use LAG()-to get previous record data and DATEDIFF- to get the date/hour difference
SELECT ID,Name ,Startdate,EndDate,
DATEDIFF(HOUR,
LAG(EndDate) OVER(PARTITION BY ID ORDER BY Startdate),
Startdate) AS Hours_Diff
FROM TABLE1
ORDER BY ID,Startdate
Result :-
ID Name Startdate EndDate Hours_Diff
1 BILL 2017-10-10 09:00 2017-10-10 19:00 NULL
1 BILL 2017-10-11 09:00 2017-10-11 19:00 14
1 BILL 2017-10-15 09:00 2017-10-15 15:00 86
1 BILL 2017-10-22 09:00 2017-10-22 11:00 162
2 TOM 2017-10-10 09:00 2017-10-10 14:00 NULL
2 TOM 2017-10-12 09:00 2017-10-12 16:00 43
3 SAM 2017-10-13 09:00 2017-10-13 20:00 NULL
3 SAM 2017-10-14 09:00 2017-10-14 19:00 13

SQL calculate Datediff for half of the 8 working day

I need to compare 2 dates and return the number of days in between. Here is a table as example:
+----+--------+-------------------------+-------------------------+
| id | userid | datestarted | datefinished |
+----+--------+-------------------------+-------------------------+
| | | | |
| 1 | 23 | 2014-03-25 09:05:00.000 | 2014-03-25 12:15:00.000 |
| 2 | 43 | 2014-03-25 09:05:00.000 | 2014-03-25 12:15:00.000 |
| 3 | 23 | 2014-03-31 09:05:00.000 | 2014-03-31 12:15:00.000 |
| 4 | 12 | 2014-03-25 09:05:00.000 | 2014-03-26 12:15:00.000 |
+----+--------+-------------------------+-------------------------+
In the first 3 cases, we have the same day, only the hours don't match.
Datestarted = 2014-03-25 09:05:00.000
Datefinished = 2014-03-25 12:15:00.000
We only input hours and minutes.
Until now, wee needed only to show the difference as whole number, without decimal points, and did it like this:
DATEDIFF(carsharing.datestarted, carsharing.datefinished)
But now, we have to show the difference between the dates as 0,5 day, if it is less than 4,5 hours. If the difference is greater it should stay as 1 day.
In the more complecated last case from the table, we should also compare and show difference between two different days
Datestarted = 2014-03-25 09:05:00.000
Datefinished = 2014-03-26 12:15:00.000
Here the result should be 1,5 days
I believe this is what you're looking for - this will round the difference to 0.5 for anything under 4.5 hours in the day, and everything else over that will go to a full day:
Declare #StartDate DateTime = '2014-03-25 09:05:00.000',
#EndDate DateTime = '2014-03-26 12:15:00.000'
;With TotalHours As
(
Select DateDiff(Minute, #StartDate, #EndDate) / 60.0 As TotalHours
)
Select Case
When TotalHours % 24 = 0
Then Floor(TotalHours / 24)
When TotalHours % 24 < 4.5
Then Floor(TotalHours / 24) + 0.5
Else Floor(TotalHours / 24) + 1.0
End As Days
From TotalHours
You can try this query. It gets the difference in minutes and multiply it by 2 in order to get a 0.5 day range. It then devide it by 24 hours and by 60 minutes before calculating the Ceiling value. Once you have it, it can be devide by 2 again.
When the value is over 4.5*24*60 (4.5 days in minutes), it only has to be devided by 24 and 60.
Query:
Select id, userid, datestarted, datefinished
, Days = Case When DATEDIFF(minute, datestarted, datefinished) > 4.5*60*24
then DATEDIFF(minute, datestarted, datefinished) / 24 / 60
else CEILING(((2.0*DATEDIFF(minute, datestarted, datefinished)) / 24 / 60)) / 2
end
From #dates
Output:
id userid datestarted datefinished Days
1 23 2014-03-25 09:05:00.000 2014-03-25 12:15:00.000 0.500000
2 43 2014-03-25 09:05:00.000 2014-03-25 12:15:00.000 0.500000
3 23 2014-03-31 09:05:00.000 2014-03-31 12:15:00.000 0.500000
4 12 2014-03-25 09:05:00.000 2014-03-26 12:15:00.000 1.500000
5 12 2014-03-25 09:05:00.000 2014-03-29 12:15:00.000 4.500000
6 12 2014-03-25 09:05:00.000 2014-03-29 22:15:00.000 4.000000
Sample Data
declare #dates table(id int, userid int, datestarted datetime, datefinished datetime);
insert into #dates(id, userid, datestarted, datefinished) values
(1, 23, '2014-03-25 09:05:00.000', '2014-03-25 12:15:00.000')
, (2, 43, '2014-03-25 09:05:00.000', '2014-03-25 12:15:00.000')
, (3, 23, '2014-03-31 09:05:00.000', '2014-03-31 12:15:00.000')
, (4, 12, '2014-03-25 09:05:00.000', '2014-03-26 12:15:00.000')
, (5, 12, '2014-03-25 09:05:00.000', '2014-03-29 12:15:00.000')
, (6, 12, '2014-03-25 09:05:00.000', '2014-03-29 22:15:00.000')
DECLARE
#StartDate datetime = '2014-03-25 09:05:00.000'
,#EndDate datetime = '2014-03-26 09:05:00.000'
;WITH d AS (SELECT DATEDIFF(d,#StartDate,#EndDate) Dys)
,h AS (SELECT DATEDIFF(hh,#StartDate,#EndDate) Hrs)
SELECT d.Dys + CASE WHEN (h.Hrs - d.Dys*24) = 0 THEN 0 ELSE CASE WHEN (h.Hrs - d.Dys*24) < 4.5 THEN 0.5 ELSE 1 END END
FROM d,h

SQL Date Range Query - Table Comparison

I have two SQL Server tables containing the following information:
Table t_venues:
venue_id is unique
venue_id | start_date | end_date
1 | 01/01/2014 | 02/01/2014
2 | 05/01/2014 | 05/01/2014
3 | 09/01/2014 | 15/01/2014
4 | 20/01/2014 | 30/01/2014
Table t_venueuser:
venue_id is not unique
venue_id | start_date | end_date
1 | 02/01/2014 | 02/01/2014
2 | 05/01/2014 | 05/01/2014
3 | 09/01/2014 | 10/01/2014
4 | 23/01/2014 | 25/01/2014
From these two tables I need to find the dates that haven't been selected for each range, so the output would look like this:
venue_id | start_date | end_date
1 | 01/01/2014 | 01/01/2014
3 | 11/01/2014 | 15/01/2014
4 | 20/01/2014 | 22/01/2014
4 | 26/01/2014 | 30/01/2014
I can compare the two tables and get the date ranges from t_venues to appear in my query using 'except' but I can't get the query to produce the non-selected dates. Any help would be appreciated.
Calendar Table!
Another perfect candidate for a calendar table. If you can't be bothered to search for one, here's one I made earlier.
Setup Data
DECLARE #t_venues table (
venue_id int
, start_date date
, end_date date
);
INSERT INTO #t_venues (venue_id, start_date, end_date)
VALUES (1, '2014-01-01', '2014-01-02')
, (2, '2014-01-05', '2014-01-05')
, (3, '2014-01-09', '2014-01-15')
, (4, '2014-01-20', '2014-01-30')
;
DECLARE #t_venueuser table (
venue_id int
, start_date date
, end_date date
);
INSERT INTO #t_venueuser (venue_id, start_date, end_date)
VALUES (1, '2014-01-02', '2014-01-02')
, (2, '2014-01-05', '2014-01-05')
, (3, '2014-01-09', '2014-01-10')
, (4, '2014-01-23', '2014-01-25')
;
The Query
SELECT t_venues.venue_id
, calendar.the_date
, CASE WHEN t_venueuser.venue_id IS NULL THEN 1 ELSE 0 END As is_available
FROM dbo.calendar /* see: http://gvee.co.uk/files/sql/dbo.numbers%20&%20dbo.calendar.sql for an example */
INNER
JOIN #t_venues As t_venues
ON t_venues.start_date <= calendar.the_date
AND t_venues.end_date >= calendar.the_date
LEFT
JOIN #t_venueuser As t_venueuser
ON t_venueuser.venue_id = t_venues.venue_id
AND t_venueuser.start_date <= calendar.the_date
AND t_venueuser.end_date >= calendar.the_date
ORDER
BY t_venues.venue_id
, calendar.the_date
;
The Result
venue_id the_date is_available
----------- ----------------------- ------------
1 2014-01-01 00:00:00.000 1
1 2014-01-02 00:00:00.000 0
2 2014-01-05 00:00:00.000 0
3 2014-01-09 00:00:00.000 0
3 2014-01-10 00:00:00.000 0
3 2014-01-11 00:00:00.000 1
3 2014-01-12 00:00:00.000 1
3 2014-01-13 00:00:00.000 1
3 2014-01-14 00:00:00.000 1
3 2014-01-15 00:00:00.000 1
4 2014-01-20 00:00:00.000 1
4 2014-01-21 00:00:00.000 1
4 2014-01-22 00:00:00.000 1
4 2014-01-23 00:00:00.000 0
4 2014-01-24 00:00:00.000 0
4 2014-01-25 00:00:00.000 0
4 2014-01-26 00:00:00.000 1
4 2014-01-27 00:00:00.000 1
4 2014-01-28 00:00:00.000 1
4 2014-01-29 00:00:00.000 1
4 2014-01-30 00:00:00.000 1
(21 row(s) affected)
The Explanation
Our calendar tables contains an entry for every date.
We join our t_venues (as an aside, if you have the choice, lose the t_ prefix!) to return every day between our start_date and end_date. Example output for venue_id=4 for just this join:
venue_id the_date
----------- -----------------------
4 2014-01-20 00:00:00.000
4 2014-01-21 00:00:00.000
4 2014-01-22 00:00:00.000
4 2014-01-23 00:00:00.000
4 2014-01-24 00:00:00.000
4 2014-01-25 00:00:00.000
4 2014-01-26 00:00:00.000
4 2014-01-27 00:00:00.000
4 2014-01-28 00:00:00.000
4 2014-01-29 00:00:00.000
4 2014-01-30 00:00:00.000
(11 row(s) affected)
Now we have one row per day, we [outer] join our t_venueuser table. We join this in much the same manner as before, but with one added twist: we need to join based on the venue_id too!
Running this for venue_id=4 gives this result:
venue_id the_date t_venueuser_venue_id
----------- ----------------------- --------------------
4 2014-01-20 00:00:00.000 NULL
4 2014-01-21 00:00:00.000 NULL
4 2014-01-22 00:00:00.000 NULL
4 2014-01-23 00:00:00.000 4
4 2014-01-24 00:00:00.000 4
4 2014-01-25 00:00:00.000 4
4 2014-01-26 00:00:00.000 NULL
4 2014-01-27 00:00:00.000 NULL
4 2014-01-28 00:00:00.000 NULL
4 2014-01-29 00:00:00.000 NULL
4 2014-01-30 00:00:00.000 NULL
(11 row(s) affected)
See how we have a NULL value for rows where there is no t_venueuser record. Genius, no? ;-)
So in my first query I gave you a quick CASE statement that shows availability (1=available, 0=not available). This is for illustration only, but could be useful to you.
You can then either wrap the query up and then apply an extra filter on this calculated column or simply add a where clause in: WHERE t_venueuser.venue_id IS NULL and that will do the same trick.
This is a complete hack, but it gives the results you require, I've only tested it on the data you provided so there may well be gotchas with larger sets.
In general what you are looking at solving here is a variation of gaps and islands problem ,this is (briefly) a sequence where some items are missing. The missing items are referred as gaps and the existing items are referred as islands. If you would like to understand this issue in general check a few of the articles:
Simple talk article
blogs.MSDN article
SO answers tagged gaps-and-islands
Code:
;with dates as
(
SELECT vdates.venue_id,
vdates.vdate
FROM ( SELECT DATEADD(d,sv.number,v.start_date) vdate
, v.venue_id
FROM t_venues v
INNER JOIN master..spt_values sv
ON sv.type='P'
AND sv.number BETWEEN 0 AND datediff(d, v.start_date, v.end_date)) vdates
LEFT JOIN t_venueuser vu
ON vdates.vdate >= vu.start_date
AND vdates.vdate <= vu.end_date
AND vdates.venue_id = vu.venue_id
WHERE ISNULL(vu.venue_id,-1) = -1
)
SELECT venue_id, ISNULL([1],[2]) StartDate, [2] EndDate
FROM (SELECT venue_id, rDate, ROW_NUMBER() OVER (PARTITION BY venue_id, DateType ORDER BY rDate) AS rType, DateType as dType
FROM( SELECT d1.venue_id
,d1.vdate AS rDate
,'1' AS DateType
FROM dates AS d1
LEFT JOIN dates AS d0
ON DATEADD(d,-1,d1.vdate) = d0.vdate
LEFT JOIN dates AS d2
ON DATEADD(d,1,d1.vdate) = d2.vdate
WHERE CASE ISNULL(d2.vdate, '01 Jan 1753') WHEN '01 Jan 1753' THEN '2' ELSE '1' END = 1
AND ISNULL(d0.vdate, '01 Jan 1753') = '01 Jan 1753'
UNION
SELECT d1.venue_id
,ISNULL(d2.vdate,d1.vdate)
,'2'
FROM dates AS d1
LEFT JOIN dates AS d2
ON DATEADD(d,1,d1.vdate) = d2.vdate
WHERE CASE ISNULL(d2.vdate, '01 Jan 1753') WHEN '01 Jan 1753' THEN '2' ELSE '1' END = 2
) res
) src
PIVOT (MIN (rDate)
FOR dType IN
( [1], [2] )
) AS pvt
Results:
venue_id StartDate EndDate
1 2014-01-01 2014-01-01
3 2014-01-11 2014-01-15
4 2014-01-20 2014-01-22
4 2014-01-26 2014-01-30

how to find the date difference in hours between two records with nearest datetime value and it must be compared in same group

How to find the date difference in hours between two records with nearest datetime value and it must be compared in same group?
Sample Data as follows:
Select * from tblGroup
Group FinishedDatetime
1 03-01-2009 00:00
1 13-01-2009 22:00
1 08-01-2009 03:00
2 01-01-2009 10:00
2 13-01-2009 20:00
2 10:01-2009 10:00
3 27-10-2008 00:00
3 29-10-2008 00:00
Expected Output :
Group FinishedDatetime Hours
1 03-01-2009 00:00 123
1 13-01-2009 22:00 139
1 08-01-2009 03:00 117
2 01-01-2009 10:00 216
2 13-01-2009 20:00 82
2 10:01-2009 10:00 82
3 27-10-2008 00:00 48
3 29-10-2008 00:00 48
Try this:
Select t1.[Group], DATEDIFF(HOUR, z.FinishedDatetime, t1.FinishedDatetime)
FROM tblGroup t1
OUTER APPLY(SELECT TOP 1 *
FROM tblGroup t2
WHERE t2.[Group] = t1.[Group] AND t2.FinishedDatetime<t1.FinishedDatetime
ORDER BY FinishedDatetime DESC)z