Reputation: 37440
I have an application that manages employee time sheets.
My tables look like:
TIMESHEET
TIMESHEET_ID
EMPLOYEE_ID
etc
TIMESHEET_DAY:
TIMESHEETDAY_ID
TIMESHEET_ID
DATE_WORKED
HOURS_WORKED
Each time sheet covers a 14 day period, so there are 14 TIMESHEET_DAY records for each TIMESHEET record. And if someone goes on vacation, they do not need to enter a timesheet if there are no hours worked during that 14 day period.
Now, I need to determine whether or not employees have a 7 day gap in the prior 6 months. This means I have to look for either 7 consecutive TIMESHEET_DAY records with 0 hours, OR a 7 day period with a combination of no records submitted and records submitted with 0 hours worked. I need to know the DATE_WORKED of the last TIMESHEET_DAY record with hours in that case.
The application is asp.net, so I could retrieve all of the TIMESHEET_DAY records and iterate through them, but I think there must be a more efficient way to do this with SQL.
Upvotes: 0
Views: 839
Reputation: 14944
SELECT t1.EMPLOYEE_ID, t1.TIMESHEETDAY_ID, t1.DATE_WORKED
FROM (SELECT ROW_NUMBER() OVER(PARTITION BY EMPLOYEE_ID, TIMESHEETDAY_ID ORDER BY DATE_WORKED) AS RowNumber,
EMPLOYEE_ID, TIMESHEETDAY_ID, DATE_WORKED
FROM (SELECT EMPLOYEE_ID, TIMESHEETDAY_ID, DATE_WORKED
FROM TIMESHEET_DAY d
INNER JOIN TIMESHEET t ON t.TIMESHEET_ID = d.TIMESHEET_ID
GROUP BY EMPLOYEE_ID, TIMESHEETDAY_ID, DATE_WORKED
HAVING SUM(HOURS_WORKED) > 0) t ) t1
INNER JOIN
(SELECT ROW_NUMBER() OVER(PARTITION BY EMPLOYEE_ID, TIMESHEETDAY_ID ORDER BY DATE_WORKED) AS RowNumber,
EMPLOYEE_ID, TIMESHEETDAY_ID, DATE_WORKED
FROM (SELECT EMPLOYEE_ID, TIMESHEETDAY_ID, DATE_WORKED
FROM TIMESHEET_DAY d
INNER JOIN TIMESHEET t ON t.TIMESHEET_ID = d.TIMESHEET_ID
GROUP BY EMPLOYEE_ID, TIMESHEETDAY_ID, DATE_WORKED
HAVING SUM(HOURS_WORKED) > 0) t ) t2 ON t1.RowNumber = t2.RowNumber + 1
WHERE t2.DATE_WORKED - t1.DATE_WORKED >= 7
Upvotes: 1
Reputation: 112279
I would do it at least partly with SQL by counting the days per timesheet and then do the rest of the logic in the program. This identifies time sheets with missing days:
SELECT * FROM
(SELECT s.timesheet_id, SUM(CASE WHEN d.hours_worked > 0 THEN 1 ELSE 0 END) AS days_worked
FROM
TimeSheet s
LEFT JOIN TimeSheet_Day d
ON s.timesheet_id = d.timesheet_id
GROUP BY
s.timesheet_id
HAVING SUM(CASE WHEN d.hours_worked > 0 THEN 1 ELSE 0 END) < 14) X
INNER JOIN TimeSheet
ON TimeSheet.timesheet_id = X.timesheet_id
LEFT JOIN TimeSheet_Day
ON TimeSheet.timesheet_id = TimeSheet_Day.timesheet_id
ORDER BY
TimeSheet.employee_id, TimeSheet.timesheet_id, TimeSheet_Day.date_worked
Upvotes: 0