在特殊条件下使用CTE

时间:2014-04-28 00:57:01

标签: sql sql-server

我在SQL Server 2005中有关于Employee - Manager层次结构的下表。

以下是我要实现的目标

enter image description here

Busienss Logic:

- 有效的经理应该有一个部门

- 有效经理是层次结构中最近的经理,其中有一个部门

- 有效部门是有效经理的部门

我已经提到CTE这样的递归方案。示例SQL SERVER – Simple Example of Recursive CTE 但我的情况比简单地找到最近的经理有更多的条件。

如何修改此CTE以获得预期结果?

QUERY

DECLARE @Emploee TABLE (EmpID INT, EmpName VARCHAR(50), Dept VARCHAR(5), Manager INT)

INSERT INTO @Emploee VALUES (1, 'A', NULL,NULL)
INSERT INTO @Emploee VALUES (2, 'B', 'D100',NULL)
INSERT INTO @Emploee VALUES (3, 'C', 'D101',2)
INSERT INTO @Emploee VALUES (4, 'D', 'D102',1)
INSERT INTO @Emploee VALUES (5, 'E', NULL,2)
INSERT INTO @Emploee VALUES (6, 'F', 'D103',5)
INSERT INTO @Emploee VALUES (7, 'G', NULL,6)
INSERT INTO @Emploee VALUES (8, 'H', 'D104',7)

SELECT * 
FROM @Emploee
WHERE Manager IS NOT NULL

2 个答案:

答案 0 :(得分:1)

WITH EmployeeManagers AS (
    SELECT Employee.EmpId
          ,1 AS Level
          ,Employee.Manager
    FROM @Employee AS Employee
    WHERE Employee.Manager IS NOT NULL
  UNION ALL
    SELECT EmployeeManagers.EmpId
          ,Level + 1 AS Level
          ,Manager.Manager
    FROM EmployeeManagers
         INNER JOIN @Employee AS Manager
             ON Manager.EmpId = EmployeeManagers.Manager
)
,EmployeeManagerDepartment AS (
    SELECT EmployeeManagers.EmpId
          ,EmployeeManagers.Level
          ,EmployeeManagers.Manager
          ,Manager.Dept
   FROM EmployeeManagers
        LEFT JOIN @Employee AS Manager
            ON Manager.EmpID = EmployeeManagers.Manager
)
,EffectiveManagerLevel AS (
    SELECT EmpId
          ,MIN(Level) EffectiveLevel
    FROM EmployeeManagerDepartment
    WHERE Dept IS NOT NULL
    GROUP BY EmpId
)
SELECT Employee.EmpID AS [Emp ID]
      ,Employee.EmpName AS [EmpName]
      ,Employee.Manager AS [Direct Manager]
      ,EmployeeManagerDepartment.Manager AS [EffectiveManager]
      ,EmployeeManagerDepartment.Dept AS [Effective Department]
FROM @Employee AS Employee
     LEFT JOIN EffectiveManagerLevel
         ON EffectiveManagerLevel.EmpId = Employee.EmpId
     LEFT JOIN EmployeeManagerDepartment
         ON EmployeeManagerDepartment.EmpId = Employee.EmpId
            AND EmployeeManagerDepartment.Level = EffectiveManagerLevel.EffectiveLevel
WHERE Employee.Manager IS NOT NULL

答案 1 :(得分:1)

有可能将adrianm答案的CTE从3减少到2,将有效管理者的数据全部合在一起

WITH EmployeeManagers AS (
  SELECT e.EmpId, e.EmpName, 1 AS Level
       , e.Manager, e.EmpID CurrLevelEmpID, Cast(Null as VarChar(5)) Dept
  FROM   Employee AS e
  WHERE  e.Manager IS NOT NULL
  UNION ALL
  SELECT em.EmpId, em.EmpName, Level + 1 AS Level
       , e.Manager, e.EmpID CurrLevelEmpID, e.Dept Dept
  FROM   EmployeeManagers em
         INNER JOIN Employee e ON e.EmpId = em.Manager
), EffectiveManagers AS (
  SELECT EmpID
       , CurrLevelEmpID Manager
       , Dept
       , Effective = ROW_NUMBER() OVER (PARTITION BY EmpID ORDER BY Level)
  FROM   EmployeeManagers e
  WHERE  DEPT is not null
)
SELECT e.EmpID
     , e.EmpName
     , e.Manager
     , eem.Manager EffectiveManager
     , eem.Dept EffectiveDepartment
FROM   Employee e
       LEFT JOIN EffectiveManagers eem ON e.EmpID = eem.EmpID 
             AND eem.Effective = 1
WHERE  e.Manager IS NOT NULL

EmployeeManagers CTE获取更多数据,特别是CurrLevelEmpID是当前级别员工的EmpID,更改e.Manager的定义将会进入定期CTE的方式,Dept是当前级别员工的部门(如果有)。
EffectiveManagers CTE为每位员工提供一个有效经理行,Effective计算员工行有效经理的级别。
主查询JOIN基表与EffectiveManagers只获得每个层次结构的第一个(有效值为1的那个)

SQLFiddle演示