Click here to Skip to main content
15,895,746 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
i have written this query to show total working time and overtime of an employee on particular date (if he has came) otherwise it doesn't show record for a person but i want if e.g. person doesn't come on particular day (e.g. sunday) then there would be obviously no InTime and EndTime so in that case it should his empid, empName etc and should put 00:00 in time columns like overtime, intime, workingtime etc but problem is that date is only entered when Intime is available but how Intime can be entered when it's holiday :(

e.g.

SQL
EmplID  EmplName ShiftID intime Outtime totalworking overtime  dateVisited
0000001 John     S001    00:00  00:00   00:00:       00:00     2013-12-01

Query:

SQL
with times as (
SELECT    t1.EmplID
        , t3.EmplName
        , min(t1.RecTime) AS InTime
        , max(t2.RecTime) AS [TimeOut]
        , t4.ShiftId as ShiftID
        , t4.StAtdTime as ShStartTime
        , t4.EndAtdTime as ShEndTime
        , cast(min(t1.RecTime) as datetime) AS InTimeSub
        , cast(max(t2.RecTime) as datetime) AS TimeOutSub
        , t1.RecDate AS [DateVisited]
FROM  AtdRecord t1 
INNER JOIN 
      AtdRecord t2 
ON    t1.EmplID = t2.EmplID 
AND   t1.RecDate = t2.RecDate
AND   t1.RecTime < t2.RecTime
inner join 
      HrEmployee t3 
ON    t3.EmplID = t1.EmplID 
inner join AtdShiftSect t4
ON t3.ShiftId = t4.ShiftId
group by 
          t1.EmplID
        , t3.EmplName
        , t1.RecDate
        , t4.ShiftId 
        , t4.StAtdTime 
        , t4.EndAtdTime
)
SELECT 
 EmplID
,EmplName
,ShiftId As ShiftID
,InTime
,[TimeOut]
,convert(char(5),cast([TimeOutSub] - InTimeSub as time), 108) TotalWorkingTime
,[DateVisited]
,CASE WHEN [InTime] IS NOT NULL AND [TimeOut] IS NOT NULL THEN
     CONVERT(char(5),CASE WHEN  CAST([TimeOutSub] AS DATETIME) >= ShEndTime And ShiftID = 'S002' Then  LEFT(CONVERT(varchar(12), DATEADD(ms, DATEDIFF(ms, CAST(ShEndTime AS DATETIME),CAST([TimeOutSub] AS DATETIME)),0), 108),5) 
                          WHEN  CAST([TimeOutSub] AS DATETIME) >= ShEndTime And ShiftID = 'S001' Then  LEFT(CONVERT(varchar(12), DATEADD(ms, DATEDIFF(ms, CAST(ShEndTime AS DATETIME),  CAST([TimeOutSub] AS DATETIME)),0), 108),5) 
      ELSE '00:00' END, 108) 
 ELSE 'ABSENT' END AS OverTime
 FROM times  order by EmplID, ShiftID, DateVisited
Posted

As you say, you don't have the information about employee no being in at a particular day. Hence you need to manufacture those records. What you need is a calendar table i.e. a table with all days you are interested in. This is not exact query but should you give the general idea:

SQL
SELECT 
    e.id,
    e.name,
    COALESCE(a.InTime, cast('00:00' as TIME)) as InTime
FROM empoyees e
CROSS JOIN calendar c
LEFT JOIN attendance a 
    ON a.date = c.date 
    AND a.empolyee_id = e.employee_id


The CROSS JOIN will give you all possible combinations of employee and date. The LEFT JOIN will then append attendance records for given day/employee if found, COALESCE will provide the default value if not not found.

See this example on SqlFiddle
 
Share this answer
 
In addition to Tomas's solution, you can use recursive queries, like this:
SQL
;with minmax as(
SELECT Convert(DATE, MIN(RecDate)) mindt,
Convert(DATE, MAX(RecDate)) maxdt FROM AtdRecord),
alldates AS( SELECT mindt as dt FROM minmax
UNION ALL
SELECT DateAdd(day, 1, a.dt) dt FROM alldates a cross join minmax m WHERE a.dt < m.maxdt
),
times as (
SELECT    t1.EmplID
        , t3.EmplName
        , min(t1.RecTime) AS InTime
        , max(t2.RecTime) AS [TimeOut]
        , t4.ShiftId as ShiftID
        , t4.StAtdTime as ShStartTime
        , t4.EndAtdTime as ShEndTime
        , cast(min(t1.RecTime) as datetime) AS InTimeSub
        , cast(max(t2.RecTime) as datetime) AS TimeOutSub
        , t1.RecDate AS [DateVisited]
FROM  AtdRecord t1 
INNER JOIN 
      AtdRecord t2 
ON    t1.EmplID = t2.EmplID 
AND   t1.RecDate = t2.RecDate
AND   t1.RecTime < t2.RecTime
inner join 
      HrEmployee t3 
ON    t3.EmplID = t1.EmplID 
inner join AtdShiftSect t4
ON t3.ShiftId = t4.ShiftId
group by 
          t1.EmplID
        , t3.EmplName
        , t1.RecDate
        , t4.ShiftId 
        , t4.StAtdTime 
        , t4.EndAtdTime
)
SELECT 
 EmplID
,EmplName
,ShiftId As ShiftID
,InTime
,[TimeOut]
,convert(char(5),cast([TimeOutSub] - InTimeSub as time), 108) TotalWorkingTime
,a.dt AS [DateVisited]
,CASE WHEN [InTime] IS NOT NULL AND [TimeOut] IS NOT NULL THEN
     CONVERT(char(5),CASE WHEN  CAST([TimeOutSub] AS DATETIME) >= ShEndTime And ShiftID = 'S002' Then  LEFT(CONVERT(varchar(12), DATEADD(ms, DATEDIFF(ms, CAST(ShEndTime AS DATETIME),CAST([TimeOutSub] AS DATETIME)),0), 108),5) 
                          WHEN  CAST([TimeOutSub] AS DATETIME) >= ShEndTime And ShiftID = 'S001' Then  LEFT(CONVERT(varchar(12), DATEADD(ms, DATEDIFF(ms, CAST(ShEndTime AS DATETIME),  CAST([TimeOutSub] AS DATETIME)),0), 108),5) 
      ELSE '00:00' END, 108) 
 ELSE 'ABSENT' END AS OverTime
 FROM alldates a LEFT JOIN times ON a.dt = times.[DateVisited] order by EmplID, ShiftID, a.dt
OPTION (MAXRECURSION 0)
 
Share this answer
 
v2
Comments
Hunain Hafeez 6-Feb-14 1:06am    
great sir but one problem, it disables whole record i want only Null in InTime,OutTime, Overtime and TotalWorkingTime. I want to display Empid, EmpName, ShiftID,
chaau 6-Feb-14 1:41am    
Yes, you are right. Use COALESCE function, as Tomas suggested to replace the Null values with the '00:00'

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900