为MS-Access编写一个困难的查询(没有MINUS操作,3个表连接)

时间:2012-06-19 13:23:01

标签: sql database ms-access

我来这里寻求复杂查询的帮助。我为此尝试了很多不同的东西,并没有得到我想要的结果。我的模式的淡化版本如下:有问题的三个表是Employees表,EmployeeTraining表和RequiredTraining表。 employees表包含员工的信息,例如empID,姓名,地址,电子邮件,positionWorked等.EmployeeTraining表包含empID和TrainingName。RequiredTraining表有一个Position和TrainingName。

员工: empID ,              名称,              位置

EmployeeTraining: empID ,                   的 trainingName

requiredTraining:职位,                    的 trainingName

以下是一些示例数据,只是为了进一步澄清:

员工

              *EMPID~~Name~~Position~~
                  1      Ted     Accountant

                  2      Bob     Janitor

employeeTraining

                 **empID~~TrainingName**
                    1          Crunching Numbers

                    1          Microsoft Excel

                    1          Using an Abicus

                    2          Lemon Pledge 100

                    2          Scrubbing Toilets

requiredTraining

                  **position**~~**TrainingName**


                    Accountant    Crunching Numbers

                    Accountant    Microsoft Excel

                    Accountant    Using an Abicus

                    Accountant    TPS Reports

                    Janitor       Lemon Pledge 100

                    Janitor       Scrubbing Toilets

在英语中,从长远来看,我想从一个表单中选择一个员工,并有一个子表单显示该员工完成的所有培训(SELECT * FROM Employees INNER JOE EmployeeTraining on employees.empid = employeetraining.empID WHERE empID = me.empID)

我还想要另一个子表单,其中显示员工尚未完成的培训,这是当前职位所必需的。这是我在努力的地方。我对使用MS Access的查询构建器不熟悉或不熟悉,但我尝试过“查找无法匹配的”查询以及尝试编写自己的查询。这似乎是MINUS操作可行,但MS Access不支持MINUS。我已尝试使用null谓词的LEFT JOIN以及上述查询中的NOT IN到requiredTraining表的查询,但我没有得到我正在寻找的结果。

例如,我正在尝试为此示例数据编写的查询结果为:

代表employeeID 1(特别是会计师)

需要“TPS报告”培训

员工2(Bob the Janitor)

鲍勃已经完成了他所有的职位培训。

我正在尝试的尝试查询的示例是:

      SELECT employees.position,employeeTraining.empid,employeetraining.TrainingName          
      FROM EmployeeTraining 
      InNER JOIN Employees ON EmployeeTraining.empid = employees.empid
      WHERE empid = '1'
      LEFT JOIN
      SELECT TrainingName,Position FROM requiredTraining
      ON EmployeeTraining.Training = RequiredTraining.Training
      WHERE (((EmployeeTraining.Training is Null)))

编辑:此问题已得到解答。谢谢大家的帮助。您的查询虽然各不相同,但都完成了目标。

4 个答案:

答案 0 :(得分:1)

以下查询应返回所有具有他们需要完成的培训名称的员工:

select e.emp_id, rt.TrainingName
from employees e left outer join
     RequiredTraining rt
     on e.position = rt.position
where rt.TrainingName not in (select TrainingName from EmployeeTraining et where et.empId = e.EmpId)

“from”子句中的联接可找到所有必需的培训。然后,“where”子句使用相关子查询来查找员工尚未完成的子查询。

答案 1 :(得分:1)

你实际上非常接近,你的其他查询...你可能会尝试NOT IN子句。例如,正如您所说,您可以让所有完成特定培训的员工都这样:

SELECT e.empID, e.name, e.Position, et.TrainingName
FROM Employees e
JOIN EmployeeTraining et ON e.empID = et.empID
WHERE empID = me.empID

您现在想要的是,所有尚未完成培训的员工......您可以在trainingName表上进行联接,确保培训类型不在您已经创建的查询中,例如这样:

SELECT e.empID, e.name, e.Position, rt.TrainingName
FROM Employees e
JOIN requiredTraining rt ON e.Position = rt.Position
WHERE rt.TrainingName NOT IN
(
   SELECT et.TrainingName
   FROM Employees e
   JOIN EmployeeTraining et ON e.empID = et.empID
   WHERE empID = me.empID
)
  AND e.empID = me.empID

请注意,如上所述,您实际上不需要加入employees表...您可以使用以下内容:

SELECT e.empID, e.name, e.Position, rt.TrainingName
FROM Employees e
JOIN requiredTraining rt ON e.Position = rt.Position
WHERE rt.TrainingName NOT IN
(
   SELECT et.TrainingName
   FROM EmployeeTraining
   WHERE et.empID = me.empID
)
  AND e.empID = me.empID

答案 2 :(得分:1)

下面的查询是从两个带有SQL剪切的MS Access查询创建的,并粘贴到派生表中。这两个查询选择具有当前培训的员工(#1)和具有所需培训的员工(#2)。它不可更新,但易于创建。您可以通过在末尾添加一行来仅显示缺少的培训:

WHERE et.TrainingName Is Null

要选择单个员工,您可以添加一行:

WHERE rt.EMPID=1 AND et.TrainingName Is Null

但是,您提到了一个子表单,因此我希望您希望使用链接子字段和主字段来限制员工。

SQL

SELECT rt.empid,
       rt.position,
       rt.trainingname,
       et.trainingname AS IsTrained
FROM   (SELECT employees.empid,
               requiredtraining.position,
               requiredtraining.trainingname
        FROM   employees
               INNER JOIN requiredtraining
                       ON employees.position = requiredtraining.position) AS rt
       LEFT JOIN (SELECT employees.empid,
                         employees.position,
                         employeetraining.trainingname
                  FROM   employees
                         INNER JOIN employeetraining
                                 ON employees.empid = employeetraining.empid) AS
                 et
              ON ( rt.trainingname = et.trainingname )
                 AND ( rt.position = et.position )
                 AND ( rt.empid = et.empid ); 

答案 3 :(得分:1)

以下查询根据您使用Access 2007测试的示例数据返回此结果集。

EMPID Position    TrainingName
1     Accountant  TPS Reports

SELECT
    sub.EMPID,
    sub.Position,
    sub.TrainingName
FROM
    (
        SELECT
            e.EMPID,
            e.Position,
            rt.TrainingName
        FROM
            Employees AS e
            INNER JOIN RequiredTraining AS rt
            ON e.Position = rt.position
    ) AS sub
    LEFT JOIN EmployeeTraining AS et
    ON
            sub.TrainingName = et.TrainingName
        AND sub.EMPID = et.empID
WHERE et.TrainingName Is Null;