Reputation: 1495
I'm working on a report and I want to display the total time an employee have spent in office for each day. An employee makes in and out of office multiple times so each time the data gets saved. I have table and records like this.
CREATE TABLE Attendance
(
ID Int,
TimeIn datetime,
TimeOut datetime
);
INSERT INTO Attendance VALUES (1, '2018-01-18 09:37:25.000', '2018-01-18 11:12:25.000');
INSERT INTO Attendance VALUES (1, '2018-01-18 11:21:25.000', '2018-01-18 16:32:25.000');
INSERT INTO Attendance VALUES (1, '2018-01-18 16:37:25.000', '2018-01-18 17:55:25.000');
INSERT INTO Attendance VALUES (2, '2018-01-18 09:56:25.000', '2018-01-18 14:37:25.000');
INSERT INTO Attendance VALUES (2, '2018-01-18 15:00:25.000', '2018-01-18 18:27:25.000');
INSERT INTO Attendance VALUES (1, '2018-01-19 09:12:25.000', '2018-01-19 11:41:25.000');
INSERT INTO Attendance VALUES (1, '2018-01-19 13:23:25.000', '2018-01-19 13:31:25.000');
INSERT INTO Attendance VALUES (2, '2018-01-19 09:12:25.000', '2018-01-19 09:59:25.000');
INSERT INTO Attendance VALUES (2, '2018-01-19 12:55:25.000', '2018-01-19 13:12:25.000');
INSERT INTO Attendance VALUES (2, '2018-01-19 14:01:25.000', '2018-01-19 18:10:25.000');
INSERT INTO Attendance VALUES (1, '2018-01-19 17:31:25.000', '2018-01-19 18:51:25.000');
I want the result to be displayed like this.
ID TimeIn TimeOut TimeIn TimeOut TimeIn TimeOut TimeSpent Day
1 Calculated Hours 2018-01-18
2 Calculated Hours 2018-01-18
1 Calculated Hours 2018-01-19
2 Calculated Hours 2018-01-19
And if possible can we make the TimeIn and TimeOut be displayed as well dynamically ?
Upvotes: 0
Views: 243
Reputation: 12544
The grouping itself can be done with a regular group by, but perhaps are stuck by grouping on the date? If so, the group by clause can have the same cast/conversions used in the display:
SELECT ID, sum(DATEDIFF(MINUTE, TimeIn,TimeOut)) TotalMinutes,CAST(TimeIn as date) Day
FROM Attendance
group by ID, CAST(TimeIn as date)
Subsequently, formatting of the time can be done with
select ID, format(TotalMinutes / 60, '0') + ':' + format(TotalMinutes % 60, '00'), Day
from(
SELECT ID, sum(DATEDIFF(MINUTE, TimeIn,TimeOut)) TotalMinutes,CAST(TimeIn as date) Day
FROM @Attendance
group by ID, CAST(TimeIn as date)
) a
Hadn't seen the added info on the dynamic columns yet. Will try to dive into that later
edit A possibility for the In/Out columns:
;with a as
(
select *, cast(TimeIn as date) Day ,
format(dateadd(MINUTE, sum( DATEDIFF( MINUTE , TimeIn,TimeOut)) over (partition by ID,cast(TimeIn as date)),0),'H:mm') TimeSpent,
cast(row_number() over (partition by ID, cast(TimeIn as date) order by TimeIn) as varchar) rnr
from Attendance
)
select * from
(select ID, Day, TimeSpent, 'In' + rnr Name, FORMAT(TimeIn, 'H:mm') T from a
union all
select ID, Day, TimeSpent,'Out' +rnr, FORMAT(TimeOut, 'H:mm') from a) u
pivot(min(T) for Name in ([In1], [Out1], [In2], [Out2],[In3],[Out3], [In4], [Out4])) p --as much as desired
Upvotes: 1
Reputation: 4146
Find an employee with maximum number of in/outs in a single day. And change number of columns in the query according to that
select
id, day, TimeIn = max(iif(rn = 1, TimeIn, '')), TimeOut = max(iif(rn = 1, TimeOut, ''))
, TimeIn = max(iif(rn = 2, TimeIn, '')), TimeOut = max(iif(rn = 2, TimeOut, ''))
, TimeIn = max(iif(rn = 3, TimeIn, '')), TimeOut = max(iif(rn = 3, TimeOut, ''))
, TimeIn = max(iif(rn = 4, TimeIn, '')), TimeOut = max(iif(rn = 4, TimeOut, ''))
, TimeIn = max(iif(rn = 5, TimeIn, '')), TimeOut = max(iif(rn = 5, TimeOut, ''))
, TimeSpent = concat(right(concat('0',sum(TimeSpent) / 60),2), ':', right(concat('0',sum(TimeSpent)%60),2))
, Day
from (
select
id, cast(TimeIn as date) day, TimeIn = convert(char(8), TimeIn, 108)
, TimeOut = convert(char(8), TimeOut, 108)
, datediff(mi, TimeIn, TimeOut) TimeSpent
, row_number() over (partition by id, cast(TimeIn as date) order by TimeIn) rn
from
@Attendance
) t
group by id, day
Upvotes: 1