You had the right idea using ROW_NUMBER and modulus (%) you were just slightly over-complicating things.
This query gets the data in a tidy format
select E.PunchID, iDateTime,
CASE WHEN ((ROW_NUMBER() OVER(partition BY [sEnrollNumber] ORDER BY [iDateTime] ASC))%2) = 0 THEN 'IN' ELSE 'OUT' END as InOut,
Cast(iDatetime as date) as date2, ShiftId
from #EmpMaster E
inner join #MachinePunchingData M ON E.PunchID=M.sEnrollNumber
ORDER BY iDateTime
Note I've removed the checks on Punch Number and Dates for now to make things clearer, but included the Shift Id (why will become apparent) Result:
3 2018-04-03 07:11:10.000 OUT 2018-04-03 1
3 2018-04-03 23:11:19.000 IN 2018-04-03 1
3 2018-04-03 23:40:29.000 OUT 2018-04-03 1
3 2018-04-04 00:11:32.000 IN 2018-04-04 1
3 2018-04-04 01:11:34.000 OUT 2018-04-04 1
3 2018-04-04 05:12:09.000 IN 2018-04-04 1
3 2018-04-04 07:10:26.000 OUT 2018-04-04 1
3 2018-04-04 23:04:28.000 IN 2018-04-04 1
Now is the time to look at your data ... that employee seems to be in and out of the workplace many times during their shift! You might want to start with some simpler data first - exactly one entry and exactly one exit per shift.
However, sticking with what we have, you are going to want to know what time they came in, what time they went out and how long they worked, preferably all on the same row. You can use one of the
SQL Analytic Functions [
^] to do that. I'm going to use LEAD to get the "next" time
select E.PunchID,
idatetime as time1,
LEAD(iDatetime,1) OVER (partition BY [sEnrollNumber] ORDER BY [iDateTime] ASC) as time2,
CASE WHEN ((ROW_NUMBER() OVER(partition BY [sEnrollNumber] ORDER BY [iDateTime] ASC))%2) = 0 THEN 'IN' ELSE 'OUT' END as InOut,
Cast(iDatetime as date) as date2
,E.ShiftID
from #EmpMaster E
inner join #MachinePunchingData M ON E.PunchID=M.sEnrollNumber
Results:
3 2018-04-03 07:11:10.000 2018-04-03 23:11:19.000 OUT 2018-04-03 1
3 2018-04-03 23:11:19.000 2018-04-03 23:40:29.000 IN 2018-04-03 1
3 2018-04-03 23:40:29.000 2018-04-04 00:11:32.000 OUT 2018-04-03 1
3 2018-04-04 00:11:32.000 2018-04-04 01:11:34.000 IN 2018-04-04 1
3 2018-04-04 01:11:34.000 2018-04-04 05:12:09.000 OUT 2018-04-04 1
3 2018-04-04 05:12:09.000 2018-04-04 07:10:26.000 IN 2018-04-04 1
3 2018-04-04 07:10:26.000 2018-04-04 23:04:28.000 OUT 2018-04-04 1
3 2018-04-04 23:04:28.000 NULL IN 2018-04-04 1
Notice we don't have what time he left that last shift!
You're going to want to expand on this basic data to be able to get real information out of it, and notice that you're really only interested in the rows that are "IN" (the "OUT" rows actually show how long the employee was
not in work). For that I'm going to suggest you use a Common Table Expression (CTE) ... it helps to make complex queries clearer and means you can build up the query in steps, checking your results as you go
;with cte AS
(
select E.PunchID,
idatetime as time1,
LEAD(iDatetime,1) OVER (partition BY [sEnrollNumber] ORDER BY [iDateTime] ASC) as time2,
CASE WHEN ((ROW_NUMBER() OVER(partition BY [sEnrollNumber] ORDER BY [iDateTime] ASC))%2) = 0 THEN 'IN' ELSE 'OUT' END as InOut,
Cast(iDatetime as date) as date2
,E.ShiftID
from #EmpMaster E
inner join #MachinePunchingData M ON E.PunchID=M.sEnrollNumber
)
SELECT PunchID, time1,time2, date2
from cte
WHERE InOut = 'IN'
ORDER BY time1
Results:
3 2018-04-03 23:11:19.000 2018-04-03 23:40:29.000 2018-04-03
3 2018-04-04 00:11:32.000 2018-04-04 01:11:34.000 2018-04-04
3 2018-04-04 05:12:09.000 2018-04-04 07:10:26.000 2018-04-04
3 2018-04-04 23:04:28.000 NULL 2018-04-04
That should keep you going for a while.