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

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

Related

Joining two tables on a column value with sorting according to other columns

I am trying to join these two tables
Table 1
Subject_id time_x x_value
---------- ------ -------
123 12:00 4
123 15:00 3
123 19:00 2
123 21:00 1
Table 2
Subject_id time_y y_value
---------- ------- --------
123 13:00 22
123 14:00 25
123 15:00 24
123 16:00 36
123 17:00 22
123 18:00 25
123 19:00 26
123 20:00 45
on column subject_id and the result has to be like below
Result
Subject_id x_value y_value time_x time_y
---------- ------- ------- ------ ------
123 4 null 12:00 12:00
123 null 22 13:00 13:00
123 null 25 14:00 14:00
123 3 24 15:00 15:00
123 null 36 16:00 16:00
123 null 22 17:00 17:00
123 null 25 18:00 18:00
123 2 26 19:00 19:00
123 null 45 20:00 20:00
123 1 null 21:00 21:00
So can you please help me to achieve these results.
You could use a select union for obtain all the time and then left join with each table
select t.subject_id, t1.x_value, t2.y_value, t.my_time time_x, t.my_time time_y
from (
select subject_id, time_x my_time
from table1
union
select subject_id, time_y
from table2
) t
left join table1 t1 on t.subject_id = t1.subject_id
and t.my_time = t1.time_x
left join table2 t2 on t.subject_id = t2.subject_id
and t.my_time = t2.time_y
I don't see why you have two time columns. So, I think you want:
select coalesce(t1.subject_id, t2.subject_id) as subject_id,
t1.x_value, t2.y_value,
coalesce(t1.time_x, t2.time_y) as time
from table1 t1 full join
table2 t2
on t2.subject_id = t1.subject_id and t2.time_y = t1.time_x;
You can duplicate the time column if you like, but I don't think that is necessary.

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

SQL Server 2000 - Row of data based on closest date

I have two tables as below and I want to return the rows for CARE_ID and WHO_STATUS where the MDT_DATE is the closest date that is <= the earliest SURGERY_DATE for each CARE_ID.
For instance for CARE_ID 5 the closest MDT_DATE which is <= the earliest SURGERY_DATE of 18/07/2009 is 17/07/2009 so the WHO_STATUS would be 2, and so on.
The script below works fine in SQL Server 2005 but it isn't backwards compatible with SQL Server 2000.
How could I rework this script so it will run in SQL Server 2000?
CARE_ID SURGERY_DATE
5 18/07/2009 00:00
5 23/07/2009 00:00
5 23/07/2009 00:00
5 23/07/2009 00:00
5 01/09/2009 00:00
5 03/09/2009 00:00
70 20/07/2009 00:00
70 21/07/2009 00:00
76 03/03/2010 00:00
78 08/07/2009 00:00
81 27/07/2009 00:00
82 27/07/2009 00:00
83 30/07/2009 00:00
86 29/07/2009 00:00
91 30/07/2009 00:00
103 03/08/2009 00:00
106 05/08/2009 00:00
125 07/08/2009 00:00
172 19/05/2010 00:00
CARE_ID MDT_DATE WHO_STATUS
5 17/07/2009 00:00 2
5 03/11/2009 00:00 1
70 23/03/2010 00:00 0
81 03/11/2009 00:00 1
81 18/11/2009 00:00 1
81 27/11/2009 00:00 3
81 27/03/2010 00:00 1
103 03/12/2008 00:00 0
103 04/01/2009 00:00 2
103 06/01/2010 00:00 1
103 08/02/2010 00:00 1
103 14/01/2013 00:00 1
172 20/07/2009 00:00 4
172 08/01/2010 00:00 3
172 25/09/2010 00:00 1
The query (working in SQL Server 2005):
SELECT t1.*,t2.WHO_STATUS
FROM (SELECT ROW_NUMBER() OVER (PARTITION BY CARE_ID ORDER BY SURGERY_DATE) AS Seq,*
FROM Table1)t1
CROSS APPLY(SELECT TOP 1 WHO_STATUS FROM Table2
WHERE CARE_ID = t1.CARE_ID
AND MDT_DATE < = t1.SURGERY_DATE
ORDER BY MDT_DATE DESC)t2
WHERE t1.Seq=1
You can use a correlated subquery for this:
select t1.*,
(select top 1 who_status
from table2 t2
where t2.care_id = t1.care_id and
t2.mdt_date <= t1.surgery_date
order by t2.mdt_date desc
) as who_status
from Table1 t1;
This will also work in SQL Server 2005.

SQL server out of hour calculation

Out of hour calculation
An out of hour calendar defined as below,Here WeekNumber starts from 1 = Monday to 5 = Friday
CalendarId WeekNumber StartTime EndTime
600 1 1900-01-01 00:00 1900-01-01 08:00
600 1 1900-01-01 18:00 1900-01-01 23:59
600 2 1900-01-01 00:00 1900-01-01 08:00
600 2 1900-01-01 18:00 1900-01-01 23:59
600 3 1900-01-01 00:00 1900-01-01 08:00
600 3 1900-01-01 18:00 1900-01-01 23:59
600 4 1900-01-01 00:00 1900-01-01 08:00
600 4 1900-01-01 18:00 1900-01-01 23:59
600 5 1900-01-01 00:00 1900-01-01 08:00
600 5 1900-01-01 18:00 1900-01-01 23:59
I would like to apply this calendar to another table called events to find records falls in these day and times ?
Edit
The Structure of event table as follows
EventID StartDateTime TotalTimeInSec WeekNumber
1 2009-07-05 07:44 100 1
2 2009-07-05 08:40 200 1
3 2009-07-05 09:35 150 1
4 2009-07-05 10:37 200 1
5 2009-07-05 19:37 200 1
6 2009-07-05 20:37 200 1
The required output will be after appyling the calendar
EventID StartDateTime TotalTimeInSec WeekNumber
1 2009-07-05 07:44 100 1
5 2009-07-05 19:37 200 1
6 2009-07-05 20:37 200 1
Select a.WeekNumber,a.startDateTime,b.starttime,b.EndTime
from tblEvents a,(Select WeekNumber,Starttime,EndTime from tblMain) b
where a.startDateTime between b.starttime and b.EndTime
and a.WeekNumber = b.WeekNumber
Select E.*
From tblEvent E
Full outer Join tblMain M on E.WeekNumber = M.WeekNumber
Where E.StartDateTime Between M.StartTime and M.EndTime
I don't believe a full outer join is what you're asking for. And the other answer didn't seem to handle your method of storing time ranges as datetime values. The only tricky part seems to be handling that date math. You can find different ways to do that check, but I think this is one solution.
SELECT e.*
FROM
Events as e INNER JOIN Calendar as c
ON c.WeekNumber = e.WeekNumber
WHERE
/* CAST(CAST(e.StartDateTime AS TIME) AS DATETIME) -- later versions */
e.StartDateTime - DATEADD(dd, DATEDIFF(dd, 0, e.StartDateTime), 0)
BETWEEN c.StartTime and e.EndTime

SQL How Many Employees Are Working, Group By Hour

I have a table, a timetable, with check-in and check-out times of the employees:
ID Date Check-in Check out
1 1-1-2011 11:00 18:00
2 1-1-2011 11:00 19:00
3 1-1-2011 16:00 18:30
4 1-1-2011 17:00 20:00
Now I want to know how many employees are working, every (half) hour.
The result I want to see:
Hour Count
11 2
12 2
13 2
14 2
15 2
16 3
17 3
18 2,5
19 1
Every 'Hour' you must read as 'till the next full hour', ex. 11 -> 11:00 - 12:00
Any ideas?
Build an additional table, called Hours, containing the following data:
h
00:00
00:30
01:00
...
23:30
then, run
Select h as 'hour' ,count(ID) as 'count' from timetable,hours where [Check_in]<=h and h<=[Check_out] group by h