Расширенный запрос с небольшим количеством логики - PullRequest
1 голос
/ 05 января 2012

У меня есть расширенный запрос / отчет, который мне нужно создать в Access 2007. Сгенерированный мной запрос:

Employee Last, Employee First, Employee Role, Course Name, StartDate, EndDate, Attended

Логика, которая мне нужна, это:

  1. ЕСЛИ пользователь посещал курс с сотрудникомerole = courserole, Присутствовал = да
  2. Если пользователь не посещал курс с Employeerole = courserole, Присутствовал = нет
  3. Если пользователь не посещал и нет курса с соответствием CourseRole, Attended = Нет курса с этой ролью

Некоторую дополнительную логику, которую было бы неплохо добавить: Trainer Last to the Select
Логика: если данные равны Null, последний тренер = нет назначенного тренера

Это не позволит мне опубликовать изображение базы данных. Итак, вот таблицы со ссылочной целостностью:

Tables:  Fields
Employee: Employee_PK, Employee_Last, Employee_first, Employee_userid   
Role: Role_PK, RoleNAme  
EmployeeRole: EmployeeRole_PK, Employee_ID, Role_ID  
Location: Location_PK, Location  
Course: Course_PK, StartDate, EndDate, CourseName, CourseNotes, Location_ID  
CourseAttendance: CourseAttendance_PK, Course_ID, Employee_ID  
CourseRole: CourseRole_PK, Course_ID, Role_ID  
Trainer: Trainer_PK, TrainerLast, TrainerFirst  
TrainerCourse:Trainer_PK, Trainer_ID, Course_ID  

Таким образом, вы можете видеть, что оно нормализовано и требуется несколько таблиц «многие ко многим»
PK для первичного ключа, ID используется в качестве внешнего ключа. Так что да, это нормально.

EDIT:
Этот запрос был размещен в комментариях:
Я пробовал несколько запросов.

SELECT qryEmployeeCoursesForRole.*, IIf(IsNull([courseattendance_PK]),"No","Yes") AS Attended 
FROM qryEmployeeCoursesForRole 
LEFT JOIN CourseAttendance 
    ON (qryEmployeeCoursesForRole.COURSE_ID = CourseAttendance.COURSE_ID) 
    AND (qryEmployeeCoursesForRole.EMPLOYEE_ID = CourseAttendance.EMPLOYEE_ID);  

Этот не обрабатывает исключение "Не определен курс" -

Course Table:
COURSE_PK   START DATE  END DATE    COURSENAME    NOTES         LOCATION_ID  
1           12/2/2012   12/2/2012   OTC           No Notes            3  
2           12/1/2012   12/1/2012   OTC           No Note             2   
3           1/5/2012    1/5/2012    Requistions  Text Text Text       1 
                                      and P-Cards

CourseAttendance Table:
COURSEATTENDANCE_PK COURSE_ID   EMPLOYEE_ID  
1                   1               1  
2                   2               2  

CourseRole Table:
COURSEROLE_PK   COURSE_ID   ROLE_ID  
1                   1         1  
2                   1         2  
3                   1         3  
4                   2         1  
5                   2         2  

Employee Table:
EMPLOYEE_PK EMPLOYEE_LAST   EMPLOYEE_FIRST  EMPLOYEE_USERID  
1              Ables        Christopher        LG854  
2              Ables        Gary               LC876  
3              Ables        Steven             LQ875  

EmployeeRole Table:
EMPLOYEEROLE_PK EMPLOYEE_ID ROLE_ID  
1                     1         1  
2                     1         2  
3                     1         3  
4                     2         1  
5                     2         2  
6                     3         4  

Location Table:
LOCATION_PK LOCATION  
1             New York  
2             New Brunfels  
3             Ontario  
4             China  

Role Table:
ROLE_PK ROLENAME  
1             Service Coordinator    
2             Service Planner  
3             Service Entry  
4             AP Invoice  

Trainer Table:
TRAINER_PK  TRAINER_LAST    TRAINER_FIRST   TRAINER_USERID  
1              Brunet              Janell     
2              Gibson              Jim             hb476  
3              Taylor              Diana           hblo7hg  

TrainerCourse Table:
TRAINERCOURSE_PK    TRAINER_ID  COURSE_ID  
1                     1         1  
2                     1         2  
3                     2         2  

Теперь, когда я подробно рассмотрел логику, оказалось, что для этого потребуется нечто большее, чем просто причудливый запрос. Если вы хотите, чтобы я был более конкретным, я могу быть более конкретным, но мне потребуется загрузить документ или что-то в этом роде.

Все запросы, которые я создал, и причина запроса:

 EmployeeCourseOutsideofRole
 SELECT CourseAttendance.EMPLOYEE_ID, CourseAttendance.COURSE_ID, Course.COURSE_NAME  
 FROM Course INNER JOIN (CourseAttendance LEFT JOIN qryEmployeeCoursesForRole ON  
 (CourseAttendance.COURSE_ID = qryEmployeeCoursesForRole.COURSE_ID) AND  
 (CourseAttendance.EMPLOYEE_ID = qryEmployeeCoursesForRole.EMPLOYEE_ID)) ON Course.COURSE_PK =  
 CourseAttendance.COURSE_ID
 WHERE (((qryEmployeeCoursesForRole.EMPLOYEE_ID) Is Null) AND     
 ((qryEmployeeCoursesForRole.COURSE_ID)  
 Is Null)); 
 If Employee took a Course and the CourseRole not equal to EmployeeRole  

 EmployeeCoursesForRoleSub:
 SELECT [Employee_last] & " " & [employee_first] AS FullName, Role.ROLENAME,  
 EmployeeRole.EMPLOYEE_ID, EmployeeRole.ROLE_ID  
 FROM Role INNER JOIN (Employee INNER JOIN EmployeeRole ON Employee.EMPLOYEE_PK =  
 EmployeeRole.EMPLOYEE_ID) ON Role.ROLE_PK = EmployeeRole.ROLE_ID;
 This is a SubQuery only--for next  

 qryEmployeeCourseForRole:
 SELECT qryEmployeeCoursesForRoleSub.*, CourseRole.COURSE_ID  
 FROM qryEmployeeCoursesForRoleSub LEFT JOIN CourseRole ON qryEmployeeCoursesForRoleSub.ROLE_ID =  
 CourseRole.ROLE_ID;
 This shows courserole with matching employeerole--a subquery for next  

 EmployeeCourseForRoleWAttended:  
 SELECT qryEmployeeCoursesForRole.*, IIf(IsNull([courseattendance_PK]),"No","Yes") AS Attended  
 FROM qryEmployeeCoursesForRole LEFT JOIN CourseAttendance ON (qryEmployeeCoursesForRole.COURSE_ID =  
 CourseAttendance.COURSE_ID) AND (qryEmployeeCoursesForRole.EMPLOYEE_ID =  
 CourseAttendance.EMPLOYEE_ID);  

Дополнительные примеры данных для отладки

 Employee Table: 
 Employee_PK     Employee_Last     Employee_First  
 Autonumber       Daigle             Jake
 Autonumber       Ryder              Canen  

 Role Table:
 Role_PK    RoleName  
  5            Asset Shipper
  6            Material Controller  
  7            Material MAnager  

 EmployeeRole Table:  
 EmployeeRole_PK     Employee_ID         Role_ID  
 Autonum              Whatever Daigle is       5  
 Autonum              Whatever Daigle is       1  
 Autonum              Whatever Ryder is        5
 Autonum              Whatever Ryder is        6    

 Course Table:             
 Course_PK    Course_Name  Course_StartDate  Course_EndDate  
   4           OTC           12/8/2011        12/9/2011  

 CourseRole Table:  
 CourseRole_PK   Course_ID      Role _ID   
   6               4              1 
   7               4              7  

 CourseAttendance:
 CourseAttendance_PK      Course_ID      Employee_ID
  Autonum                  4              Whatever Daigle is
  Autonum                  4              Whatever Ryder is

Хорошо, я разместил пример данных. Проблема возникает, если пользователь посещал курс, который выполняет одну из своих ролей, и courserole = employeeerole, тогда запрос сообщает, что он выполнил ВСЕ свои роли.

Что мне нужно в одном отчете:

Фамилия сотрудника, Имя сотрудника, Роль 1, CoureName, Дата начала, Дата окончания, Участник Но логика должна быть там, как я перечислил выше в начале поста.

1 Ответ

3 голосов
/ 05 января 2012

Это немного грязно, но это должно помочь вам начать. Исходя из структур таблиц, которые у вас есть, ваш дизайн немного отличается. У вас есть таблицы с ненужными столбцами, но это не ваш вопрос.

Это можно разделить на 3 разных запроса или просто использовать UNION, как я сделал ниже:

'this first query gets you the employees who have attended
SELECT E.EmployeeLast, E.EmployeeFirst, R.RoleName AS EmployeeRole
    , C.CourseName, C.StartDate, C.EndDate, "Yes" AS Attended
FROM (((Employee AS E 
INNER JOIN EmployeeRole AS ER 
    ON E.EmployeePK=ER.EmployeeId) 
INNER JOIN Role AS R 
    ON ER.RoleID=R.RolePK) 
LEFT JOIN CourseAttendance AS CA 
    ON E.EmployeePK=CA.EmployeeID) 
LEFT JOIN Course AS C 
    ON CA.CourseID=C.CoursePK
WHERE E.EmployeePK IN (SELECT CA.EmployeeID 
                        FROM ((CourseAttendance CA 
                        INNER JOIN EmployeeRole ER 
                            ON CA.EmployeeId = ER.EmployeeId) 
                        INNER JOIN CourseRole CR 
                            ON ER.RoleId = CR.RoleId 
                            AND CA.CourseID = CR.CourseID));

UNION

'this second query gets you the employees who have not attended
SELECT E.EmployeeLast, E.EmployeeFirst, R.RoleName AS EmployeeRole
    , C.CourseName, C.StartDate, C.EndDate, "No" AS Attended
FROM (((Employee AS E 
INNER JOIN EmployeeRole AS ER 
    ON E.EmployeePK=ER.EmployeeId) 
INNER JOIN Role AS R 
    ON ER.RoleID=R.RolePK) 
LEFT JOIN CourseAttendance AS CA 
    ON E.EmployeePK=CA.EmployeeID) 
LEFT JOIN Course AS C 
    ON CA.CourseID=C.CoursePK
WHERE E.EmployeePK NOT IN (SELECT CA.EmployeeID 
                        FROM ((CourseAttendance CA 
                        INNER JOIN EmployeeRole ER 
                            ON CA.EmployeeId = ER.EmployeeId) 
                        INNER JOIN CourseRole CR 
                            ON ER.RoleId = CR.RoleId 
                            AND CA.CourseID = CR.CourseID));

UNION

'this final query gets you the employees who have not attended and there is no course with their role
SELECT E.EmployeeLast, E.EmployeeFirst, R.RoleName AS EmployeeRole
    , C.CourseName, C.StartDate, C.EndDate, "No Course With Role" AS Attended
FROM (((Employee AS E 
INNER JOIN EmployeeRole AS ER 
    ON E.EmployeePK=ER.EmployeeId) 
INNER JOIN Role AS R 
    ON ER.RoleID=R.RolePK) 
LEFT JOIN CourseAttendance AS CA 
    ON E.EmployeePK=CA.EmployeeID) 
LEFT JOIN Course AS C 
    ON CA.CourseID=C.CoursePK
WHERE ER.RoleID NOT IN (SELECT RoleID 
                        FROM CourseRole)
    AND E.EmployeePK NOT IN  (SELECT CA.EmployeeID 
                                FROM ((CourseAttendance CA 
                                INNER JOIN EmployeeRole ER 
                                    ON CA.EmployeeId = ER.EmployeeId) 
                                INNER JOIN CourseRole CR 
                                    ON ER.RoleId = CR.RoleId 
                                    AND CA.CourseID = CR.CourseID));
...