Reputation: 3566
I have the following database schema for an attendance system:
How would I write an SQL query to generate a good report of entries on day X? I need it to generate a report that has
Employee Name | TimeIn | TimeOut
Bob | 10:00 | 11:00
Sam | 10:30 | 18:00
Bob | 11:30 | 15:00
but the row that defines if it was a time in or out is set by entryType (1 being in, 0 being out), so I would aliases TimeIn and TimeOut.
My attempt was
`SELECT firstName, time from log INNER JOIN users on log.employeeID = users.employeeID WHERE date = GETDATE()`
but this doesn't handle the fact that some times are entry, some are exit.
Note that there can be multiple sign ins per date.
Update:
Another attempt, but the subquery returns multiple rows
select firstName, (select time as timeIn from log where entryType = 1), (select time as timeOut from log where entryType = 0) inner join users on log.uID = users.uID from log group by uID
Upvotes: 0
Views: 191
Reputation: 8709
This works in Oracle (apologies for the non-ANSI style, but you should get the drift)..
SELECT FORENAME,SURNAME,L1.TIME IN_TIME,L2.TIME OUT_TIME
FROM EMPLOYEES EMP, LOG L1, LOG L2
WHERE EMP.EMPLOYEE_ID = L1.EMPLOYEE_ID
AND EMP.EMPLOYEE_ID = L2.EMPLOYEE_ID
AND L1.ENTRYTYPE = 1
AND L2.ENTRYTYPE = 0
AND L2.TIME = (SELECT MIN(TIME) FROM LOG WHERE EMPLOYEE_ID = L2.EMPLOYEE_ID AND L2.ENTRYTYPE = 0 AND TIME > L1.TIME)
Update:
Ah, yes, hadn't considered that. In this case you need an outer join. something like this (untested):
SELECT FORENAME,SURNAME,L1.TIME IN_TIME,L2.TIME OUT_TIME
FROM EMPLOYEES EMP
INNER JOIN LOG L1 ON EMP.EMPLOYEE_ID = L1.EMPLOYEE_ID AND L1.ENTRYTYPE = 1
LEFT OUTER JOIN LOG L2 ON EMP.EMPLOYEE_ID = L2.EMPLOYEE_ID AND L2.ENTRYTYPE = 0
AND L2.TIME = (SELECT MIN(TIME) FROM LOG WHERE EMPLOYEE_ID = L2.EMPLOYEE_ID AND L2.ENTRYTYPE = 0 AND TIME > L1.TIME)
Upvotes: 1
Reputation: 10063
Simply this will work. Try this
SELECT FORENAME,SURNAME,LG.IN_TIME,LG.OUT_TIME FROM EMPLOYEES EMP INNER JOIN
(SELECT MIN(TIME) IN_TIME,MAX(TIME) OUT_TIME,EMPLOYEE_ID FROM LOG
GROUP BY EMPLOYEE_ID) LG ON EMP.EMPLOYEE_ID=LG.EMPLOYEE_ID
Note : I didnt include the entry type because at any time min time will be swipe in and max time will be swipe out
To show no of sign ins and outs try something like this,
SELECT FORENAME,SURNAME,LG.IN_TIME,LG.OUT_TIME,LG.no_of_ins,
LG.no_of_outs FROM EMPLOYEES EMP INNER JOIN
(SELECT MIN(TIME) IN_TIME,MAX(TIME) OUT_TIME,EMPLOYEE_ID,
COUNT( CASE WHEN ENTRY_TYPE='I' THEN 1 ELSE O END noi) no_of_ins,
COUNT( CASE WHEN ENTRY_TYPE='O' THEN 1 ELSE O END nou) no_of_outs,
GROUP BY EMPLOYEE_ID) LG ON EMP.EMPLOYEE_ID=LG.EMPLOYEE_ID
Upvotes: 1
Reputation: 30809
This query will give you the earliest time in and latest time out of an employee.
SELECT E.FORENAME,
(SELECT MIN(TIME) FROM LOG WHERE EMPLOYEEID = E.EMPLOYEEID AND ENTRYTYPE = 1 AND DATE = <YOUR DAYE>) AS "TIME_IN",
(SELECT MAX(TIME) FROM LOG WHERE EMPLOYEEID = E.EMPLOYEEID AND ENTRYTYPE = 0 AND DATE = <YOUR DAYE>) AS "TIME_OUT"
FROM EMPLOYEE E WHERE E.EMPLOYEEID = <EMPLOYEE ID>
Upvotes: 0