【问题标题】:Using CTE with special conditions在特殊条件下使用 CTE
【发布时间】:2014-04-28 22:17:53
【问题描述】:

我在SQL Server 2005 中有以下员工 - 经理层次结构表。

以下是我想要实现的目标

业务逻辑:

-- 有效的管理者应该有一个部门

-- 有效经理是层次结构中最近的具有部门的经理

-- Effective Department 是 Effective Manager 的部门

我已将CTE 用于此类递归场景。示例SQL SERVER – Simple Example of Recursive CTE 但我的情况比简单地找到最近的经理有更多的条件。

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

查询

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

【问题讨论】:

  • 嗯 - 基本上 - 你只是举个例子,然后在 CTE 的“源”部分(UNION 之前的前半部分)中扩展 FROM 和 WHERE,然后在之后扩展 ON 子句CTE 的“第二”部分(联合之后的部分)中的 INNER JOIN。在递归功能之后,一些规则可能适用——这意味着您从 CTE 中实际选择的位置。

标签: sql sql-server


【解决方案1】:

将有效经理的数据汇总在一起,可以将adrianm answer的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,并且@ 987654327@是该员工所在级别的部门,如果有的话。
EffectiveManagers CTE 为每个员工获取有效经理的行,Effective 计算员工行的有效经理的级别。
主查询JOINEffectiveManagers 的基表仅获得每个层次结构的第一个(有效= 1 的那个)

SQLFiddle演示

【讨论】:

    【解决方案2】:
    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-01
      • 2015-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多