【问题标题】:SQL Conditional JOINSQL 条件连接
【发布时间】:2011-03-29 14:35:02
【问题描述】:

我有三个表 'Employees'、'Departments' 和 'EmployeesInDepartments' “Employees”表引用“Departments”表(每个员工都必须有一个 DepartmentId)。但是,通过将条目(EmployeeId 和 DepartmentId)添加到 'EmployeeInDepartments' 表中,一个员工可以存在于多个部门中。

我目前有以下存储过程来按部门 ID 检索员工:

CREATE PROCEDURE dbo.CollectEmployeesByDepartmentId
    (
    @DepartmentId int,
    @IsDeleted bit
    )
AS
BEGIN
        SELECT   Employees.*
        FROM      Employees 
        WHERE   ((Employees.IsDeleted = @IsDeleted )
            AND ((Employees.DepartmentId = @DepartmentId)
                OR (Employees.EmployeeId IN (SELECT EmployeesInDepartments.EmployeeId
                                        FROM EmployeesInDepartments 
                                        WHERE (EmployeesInDepartments.DepartmentId = @DepartmentId)
                                        )
                    )
                )
        )   
END

如何优化此存储过程并可能使用 JOINS?

【问题讨论】:

    标签: sql sql-server sql-server-2005 tsql


    【解决方案1】:

    我给您的第一个建议是从员工表中删除部门 ID。将所有记录插入到 Departments 表中的员工中。

    那就是简单的内连接。

    当然,永远不要在生产代码中使用 select *。

    【讨论】:

    • 感谢精选*推荐。已经提出了设计变更,但尚未获得批准。转换当前数据可能需要做一些工作。
    【解决方案2】:

    这是我对您的查询的重写:

    WITH summary AS (
       SELECT e.*
         FROM EMPLOYEES e
        WHERE e.isdeleted = @IsDeleted 
          AND e.parentid = 0)
    SELECT a.*
      FROM summary a
     WHERE a.departmentid = @DepartmentId
    UNION
    SELECT b.*
      FROM summary b
      JOIN EMPLOYEESINDEPARTMENTS ed ON ed.employeeid = b.employeeid
                                    AND ed.departmentid = @DepartmentId
    

    UNION 是删除重复项所必需的 - 如果您知道永远不会有重复项,请将 UNION 更改为 UNION ALL

    称为“摘要”的 CTE 不提供任何性能优势,它只是简写。

    【讨论】:

    • 感谢 UNION 的推荐。
    【解决方案3】:
       SELECT E.*
       FROM Employees E
          Left Join EmployeesInDepartments EID ON E.EmployeeId = EID.EmployeeId
             And E.DepartmentId <> @DepartmentId 
    
       WHERE E.IsDeleted = @IsDeleted
          And
          (  
             E.DepartmentId = @DepartmentId 
             Or (EID.DepartmentId = @DepartmentId)
          )
    

    编辑以包含 IsDeleted 逻辑。 我确实同意其他一些答案,您的设计可能应该更改。但是这个查询应该这样做。如果您在EmployeesInDepartments 中有重复项,您可以将其更改为Select Distinct。

    【讨论】:

    • 这个虽然票数不多,但这就是我一直在寻找的答案。
    【解决方案4】:

    我建议您将查询中使用的IN 子句更改为WHERE EXISTS

    如果您在查询中使用IN,则意味着您没有利用表上定义的索引,并且查询将执行完整的表扫描,这会影响查询性能。

    您可以查看此线程以将IN 转换为WHERE EXISTS

    Changing IN to EXISTS in SQL

    【讨论】:

    猜你喜欢
    • 2013-05-18
    • 2014-12-25
    • 2023-04-10
    • 2012-09-17
    • 2020-05-19
    • 2015-05-13
    相关资源
    最近更新 更多