使用JOIN的SQL查询涉及来自同一个表的两个条件

时间:2015-09-06 19:25:27

标签: sql join access-vba ms-access-2010

我正在使用MS Access试图找出有效的SQL语句。在表格上,我有一个显示员工列表的组合框。我有一个单独的对话框表单,允许用户在列表框中选择多个项目。每个项目代表一个认证。每位员工都可以拥有任何数量和组合的认证。最后,我只想通过分配正确的SQL语句来更新组合框的RowSource属性以反映新的过滤数据。

如果我想过滤员工组合框中的列表,我会使用这个SQL语句:

SELECT 
    Employees.Employee_ID, Employees.Last_Name, Employees.First_Name 
FROM 
    Employees 
INNER JOIN 
    Emp_Certs ON Employees.Employee_ID = Emp_Certs.Employee_ID 
WHERE 
    (((Employees.Active_Member) = Yes) 
      AND ((Emp_Certs.Employee_ID) = [Employees].[Employee_ID]) 
     AND ((Emp_Certs.Cert_ID) = 1)) 
ORDER BY 
    Employees.Last_Name;

如果我运行此查询,它可以工作,因为我只为Emp_Certs.Cert_ID分配一个值。但当我添加另一个这样的时候:

SELECT 
    Employees.Employee_ID, Employees.Last_Name, Employees.First_Name 
FROM 
    Employees 
INNER JOIN 
    Emp_Certs ON Employees.Employee_ID = Emp_Certs.Employee_ID 
WHERE 
    (((Employees.Active_Member) = Yes) 
      AND ((Emp_Certs.Employee_ID) = [Employees].[Employee_ID]) 
      AND ((Emp_Certs.Cert_ID) = 1) 
      AND ((Emp_Certs.Cert_ID) = 4)) 
ORDER BY Employees.Last_Name;

我得到一个空集。那不是我的预期。表Emp_Certs显然有几名员工,他们拥有认证1和4的组合。 如果我想更多地指出一个Cert_ID并且员工记录只在组合框中显示一次,那么有人可以解释一下这应该如何编写。我不需要在组合框中多次显示员工记录。

这可能会有所帮助:

enter image description here

4 个答案:

答案 0 :(得分:1)

当你连接表时,你基本上查询一个结果集,其中包含那些你的where子句操作的连接表的行的所有组合。由于您只加入Emp_Certs表一次并且仅通过Employee_ID链接,因此您将得到一个如下所示的结果集(仅显示两列):

Last_Name    Cert_ID
Jones        1
Jones        3
Jones        4
Smith        1
Smith        2

您的where子句然后过滤这些行,只接受具有Cert_ID = 1 AND Cert_ID = 4的行,这是不可能的,因此您不应该获得任何行。

我不确定Access是否有限制,但在SQL Server中,您至少可以通过两种方式处理它:

1)两次链接到表格,加入每个认证。表别名'a'连接到Emp_Certs表,其中Cert_ID为1,表别名'b'连接到Cert_ID为4的Emp_Certs表:

SELECT 
    Employees.Employee_ID, Employees.Last_Name, Employees.First_Name 
FROM 
    Employees 
INNER JOIN 
    Emp_Certs a ON Employees.Employee_ID = a.Employee_ID AND a.Cert_ID = 1
INNER JOIN 
    Emp_Certs b ON Employees.Employee_ID = b.Employee_ID AND b.Cert_ID = 4
WHERE 
    Employees.Active_Member = Yes
ORDER BY Employees.Last_Name;

这为您提供了一个看起来像这样的结果集(Smith没有显示,因为加入条件不允许任何行,除非员工可以链接到表ab):

Last_Name    a.Cert_ID   b.Cert_ID
Jones        1           4

2)使用where子句中的子选择来过滤具有这些认证的ID上的员工ID(看起来像Access 2010 supports it):

SELECT 
    Employees.Employee_ID, Employees.Last_Name, Employees.First_Name 
FROM 
    Employees 
WHERE 
    Active_Member = Yes
    AND Employee_ID in (SELECT Employee_ID FROM Emp_Certs WHERE Cert_ID = 1)
    AND Employee_ID in (SELECT Employee_ID FROM Emp_Certs WHERE Cert_ID = 4)
ORDER BY Employees.Last_Name;

答案 1 :(得分:0)

您应该在OR子句中使用WHERE运算符:

WHERE 
    (((Employees.Active_Member) = Yes) 
      AND ((Emp_Certs.Employee_ID) = [Employees].[Employee_ID]) 
      AND ( Emp_Certs.Cert_ID  = 1 OR
            Emp_Certs.Cert_ID  = 4 ) 
ORDER BY Employees.Last_Name;

因为Emp_Certs.Cert_ID = 1 and Emp_Certs.Cert_ID = 4始终为FALSE

由于((Emp_Certs.Employee_ID) = [Employees].[Employee_ID])条件

INNER JOIN条件也是多余的

答案 2 :(得分:0)

您的查询无效,因为Emp_Certs可能只存储单个值。您无法检查该值是否为1和4.如果您的目标是将多个项目存储到一个字段中,请查看此处:

How to store array or multiple values in one column

最好在不同的领域存储不同的认证。

答案 3 :(得分:0)

您现在选择的是包含员工证书1和4的行。您可能希望在访问中实现这样的查询......

SELECT DISTINCT Employees.Employee_ID, Employees.Last_Name, Employee.First_Name
FROM Emp_Certs AS a 
INNER JOIN (Emp_Certs INNER JOIN Employees ON Emp_Certs.Employee_Id = Employees.Employee_ID) ON a.Employee_ID = Employees.Employee_ID
WHERE (((Emp_Certs.CertId)=1) AND ((a.CertId)=4) AND ((Employees.Active_Member)=Yes))
ORDER BY Employee.Last;

此Edit已经过测试,可以在Access中使用。它返回您请求的结果。使用查询构建器时要记住的关键是您必须两次加入Emp_Certs表。