【问题标题】:SQL query with JOIN involving two criteria from same table使用 JOIN 的 SQL 查询涉及来自同一表的两个条件
【发布时间】:2015-12-02 08:15:02
【问题描述】:

我在 MS Access 中工作,试图解决一个有效的 SQL 语句。在表单上,​​我有一个显示员工列表的组合框。我有一个单独的对话框表单,允许用户在列表框中选择多个项目。每个项目代表一个认证。每个员工都可以拥有任意数量和组合的证书。最终,我只想更新组合框的 RowSource 属性,以通过分配适当的 SQL 语句来反映新的过滤数据。

如果我想过滤员工组合框中的列表,我使用这个 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 并让员工记录在组合框中仅显示一次,有人可以解释一下应该如何编写。我不需要在组合框中多次显示员工记录。

这可能会有所帮助:

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

    1) 两次链接到表格,加入每个认证。表别名“a”连接到 Cert_ID 为 1 的 Emp_Certs 表,表别名“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;
    

    【讨论】:

    • 这帮助最大。我尝试了第一种情况,但不断收到语法错误。第二个带有子选择的工作顺利进行。谢谢
    【解决方案2】:

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

    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

    由于INNER JOIN 条件,((Emp_Certs.Employee_ID) = [Employees].[Employee_ID]) 条件也是多余的

    【讨论】:

    • 我去掉了多余的子句,但效果一样。
    • 我试过了。结果返回两个只有认证 1 的员工和两个同时拥有 1 和 4 的员工。此外,这两个员工都出现在组合框中两次。这不好。结果集应仅返回具有这两种认证的员工。不只是其中一个。
    【解决方案3】:

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

    How to store array or multiple values in one column

    您最好将不同的证书存储在不同的字段中。

    【讨论】:

    • 仅供参考..Emp_Certs 是用于处理一对多关系的链接表。它仅包含两个字段:Employee_ID 和 Cert_ID。 Employees.Employee_ID 字段指向 Emp_Certs.Employee_ID 字段,Certifications.Cert_ID 指向 Emp_Certs.Cert_ID 字段。因此,我可以在 Emp_Certs 表中放置有关同一员工的多个条目。
    【解决方案4】:

    您现在选择的是包含员工证书 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;
    

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

    【讨论】:

    • 这看起来很有希望,但是当我运行它时,我得到:语法错误(缺少运算符):(((Employees.Active_Member)= Yes)AND((a.Cert_ID)= 1))INNER JOIN Emp_Certs AS b ON Employees.Employee_ID = b.Employee_ID WHERE (((Employees.Active_Member) = Yes) A​​ND ((b.Cert_ID) = 4)) 我觉得没问题。我看不出错误在哪里。
    • 正如其他响应者之一所指出的那样,以下条件:((a.Employee_ID) = [Employees].[Employee_ID]) 可以省略,因为它是多余的并且被 INNER JOIN 语句覆盖.
    • 是的,看起来它应该可以工作,但它没有。我仍然不断收到语法错误(缺少运算符)
    • 试试这个语法。这已经在 Access 中测试过
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-20
    • 2021-12-01
    • 2014-05-08
    • 1970-01-01
    相关资源
    最近更新 更多