If you are using SQL 2012, here is the basic idea using LEAD:
SELECT ROUND(clockIn) as [date], employeeId, clockIn as clockInTime, LEAD(clockIn) OVER (PARTITION BY employeeId, ROUND(clockIn) ORDER BY clockIn) as clockOutTime FROM TimeCard WHERE clockType = 'in'
Then you can get the time by making the difference between the clock and the clock.
There are many corner cases that not all are handled here:
- can a work period last midnight?
- what if the first timeout is of type 'out'?
- What if there are two "in one" or "two times" in a line?
The fact is that the clock is processed without an exit. Since the last line of the section is LEAD NULL.
Here's a more robust option that works in SQL 2005:
WITH NumberedClockIn AS ( SELECT ROUND(clockIn) as [date], employeeId, clockIn as clockTime, clockType, ROW_NUMBER() OVER (PARTITION BY employeeId, ROUND(clockIn) ORDER BY clockIn) as rn FROM TimeCard ) SELECT IN.[date], IN.employeeId, IN.clockTime as clockInTime, OUT.clockTime as clockOutTime FROM NumberedClockIn IN LEFT OUTER JOIN NumberedClockIn OUT ON IN.[date] = OUT.[date] AND IN.employeeId = OUT.employeeID AND IN.rn + 1 = OUT.rn WHERE IN.clockType = 'in' AND OUT.clockType = 'out'
This is more complex and less efficient, but more robust in the face of invalid "in" and "out" sequences. Again, the way it handles invalid sequences may or may not be the behavior you really want.
jods source share