I think you've probably 'over normalised' your tables in the structure shown
Ranman's answer with the Cartesian join doesn't take into account the employee role related to the courses required
Here's what I would do
1. qryEmpMandTraining - courses each employee should attend
Code:
SELECT tblEmployees.EmployeeID, tblEmployees.RoleID, tblEmployees.FirstName, tblEmployees.LastName, tblEmployees.StartDate, tblMandatoryTraining.CourseIDFROM (tblMandatoryTraining INNER JOIN tblRoles ON tblMandatoryTraining.RoleID = tblRoles.RoleID) INNER JOIN tblEmployees ON tblRoles.RoleID = tblEmployees.RoleID;
2, qryEmpCourseAttendance - courses each has attended
Code:
SELECT tblCourse.CourseID, tblCourse.Course, tblCourseDetails.StartDate, tblCourseAttendance.EmployeeID
FROM (tblCourseDetails INNER JOIN tblCourse ON tblCourseDetails.CourseID = tblCourse.CourseID) INNER JOIN tblCourseAttendance ON tblCourseDetails.CourseID = tblCourseAttendance.CourseDetailsID;
3. Unmatched query qryEmpMissingTraining - linking both of these together &showing employees with missing courses
Code:
SELECT qryEmpMandTraining.EmployeeID, qryEmpMandTraining.RoleID, qryEmpMandTraining.FirstName, qryEmpMandTraining.LastName, qryEmpMandTraining.StartDate, qryEmpMandTraining.CourseIDFROM qryEmpMandTraining LEFT JOIN qryEmpCourseAttendance ON qryEmpMandTraining.EmployeeID = qryEmpCourseAttendance.EmployeeID
WHERE (((qryEmpMandTraining.StartDate)<[qryEmpCourseAttendance].[StartDate]) AND ((qryEmpCourseAttendance.EmployeeID) Is Null));
NOTE: I've also added a check to only include records where employee start date was before a course was run
A further complication is the Refresher Period - but I'll leave that to you
Attached is an empty database with these items
To save time, I've omitted any fields that aren't used in the above queries
EmpTraining.zip