【问题标题】:Using T-SQL and Joins, display a hierarchy of employees in a table使用 T-SQL 和联接,在表中显示员工的层次结构
【发布时间】:2014-01-06 04:32:14
【问题描述】:

我想生成一个这样的表:

+----------------------------------------------------------------+
| Level | PersonName | empid | ManagerID | Code   | ManagerName  |
+----------------------------------------------------------------+
| 1     | BigBoss    | 1     | null      | 00     | null         |
| 2     | Executive1 | 2     | 1         | 0001   | BigBoss      |
| 2     | Executive2 | 3     | 1         | 0002   | BigBoss      |
| 3     | Manager1   | 4     | 2         | 000101 | Executive1   |
| 3     | Manager2   | 5     | 2         | 000102 | Executive1   |
| 3     | Manager3   | 6     | 3         | 000201 | Executive2   |
+----------------------------------------------------------------+

因此,正如您所见,与经理相比,下属的代码中多了 2 个数字,Code 决定了层次结构。有时在重组过程中,员工的代码没有立即更新,因此代码变得不一致,在表中产生错误,如下所示:

+----------------------------------------------------------------+
| Level | PersonName | empid | ManagerID | Code   | ManagerName  |
+----------------------------------------------------------------+
| 1     | BigBoss    | 1     | null      | 00     | null         |
| 2     | Executive1 | 2     | 1         | 0001   | BigBoss      |
| 2     | Executive2 | 3     | 1         | 0002   | BigBoss      |
| 3     | Manager1   | 4     | 2         | 000101 | Executive1   |
| 3     | Manager2   | 5     | 2         | 000102 | Executive1   |
| 3     | Manager3   | 6     | 3         | 000201 | Executive2   |
| 3     | Manager4   | 7     | 99        | 000202 | WrongManager |
+----------------------------------------------------------------+

所以,我想添加一个条件来检查一个人的经理 ID 是否作为上述级别中的 ID 存在。例如在级别 3 中,经理 4 的经理 ID 为 99。经理 ID 99 不作为级别 2 中的人员 ID 存在,因此不应包含在内。

这是我对代码的尝试:

select 
    1 as level
    ,reportfor.preferredname + ' ' + reportfor.surname as PersonName
    ,id
    ,null as ManagerID
    ,emp.code as Code
    ,null as ManagerName
from d_edr edr
    inner join o_training_courses crs on crs.sap_course_num=edr.course_id
    inner join employees emp on emp.empid=edr.empid
    inner join employees reportfor on reportfor.code = '00'
group by 
    ,reportfor.preferredname + ' ' + reportfor.surname 
    ,id
    ,emp.code 
union 
select 
    2 as level
    ,reportfor.preferredname + ' ' + reportfor.surname as PersonName
    ,id
    ,emp.mgrid as ManagerID
    ,emp.code as Code
    ,mgr.preferredname + ' ' + mgr.surname as ManagerName
from d_edr edr
    inner join o_training_courses crs on crs.sap_course_num=edr.course_id
    inner join employees emp on emp.empid=edr.empid
    inner join employees reportfor on reportfor.code LIKE '00__'
    inner join employees mgr on mgr.empid=reportfor.mgrid
group by 
    ,reportfor.preferredname + ' ' + reportfor.surname
    ,id
    ,emp.mgrid
    ,emp.code
    ,mgr.preferredname + ' ' + mgr.surname
union 
select 
    3 as level
    ,reportfor.preferredname + ' ' + reportfor.surname as PersonName
    ,id
    ,emp.mgrid as ManagerID
    ,emp.code as Code
    ,mgr.preferredname + ' ' + mgr.surname as ManagerName
from d_edr edr
    inner join o_training_courses crs on crs.sap_course_num=edr.course_id
    inner join employees emp on emp.empid=edr.empid
    inner join employees reportfor on reportfor.code LIKE '00____'
    inner join employees mgr on mgr.empid=reportfor.mgrid
group by 
    ,reportfor.preferredname + ' ' + reportfor.surname
    ,id
    ,emp.mgrid
    ,emp.code
    ,mgr.preferredname + ' ' + mgr.surname

我希望这行代码能解决它,但它没有

inner join employees mgr on mgr.empid=reportfor.mgrid

员工表的定义是:

empid = employee id
preferred name = first name
surname = last name 
code = hierarchy code
mgrid = manager id

【问题讨论】:

  • 我只需要知道,但是如果您已经拥有 ManagerID,为什么还要输入代码?如果你有 4 级和 5 级会发生什么。你要为每个级别联合吗?
  • 对于无效的ManagerID值,为什么不添加一个自引用外键来强制引用完整性?

标签: sql sql-server tsql inner-join


【解决方案1】:

使用 CTE

WITH OrgChart AS    
(    
    SELECT  1 as level
            ,emp.preferredname + ' ' + emp.surname as PersonName
            ,id
            ,null as ManagerID
            ,emp.code as Code
            ,null as ManagerName
    FROM d_edr edr
        inner join o_training_courses crs on crs.sap_course_num=edr.course_id
        inner join employees emp on emp.empid=edr.empid
    WHERE emp.code = '00'

    UNION ALL

    SELECT OrgChart.level + 1 level
            ,emp.preferredname + ' ' + emp.surname as PersonName
            ,id
            ,null as ManagerID
            ,emp.code as Code
            ,null as ManagerName
    FROM d_edr edr
        inner join o_training_courses crs on crs.sap_course_num=edr.course_id
        inner join employees emp on emp.empid=edr.empid
        INNER JOIN OrgChart ON edr.empid = OrgChart.empid
    WHERE emp.code != '00'

)
SELECT *
FROM OrgChart;

【讨论】:

    【解决方案2】:

    不确定这是否是您正在寻找的答案,但它可能是您为每个级别选择数据而不是 UNION 的替代解决方案。

    WITH Employee_hierarchy (Level, PersonName, EmpID, ManagerID, Code, ManagerName) AS
    (
    
          SELECT 1 AS Level, base.PersonName, base.EmpID, base.mgrid, Code, convert(varchar(50), Null) ManagerName
          FROM employees base
          WHERE base.mgrid is null
          UNION all
    
          SELECT LEVEL + 1 AS Level, child.PersonName,  child.EmpID, child.mgrid, child.Code, eh.PersonName
          FROM employees child
          inner join Employee_hierarchy eh on child.mgrid = eh.EmpID
    )     
    
    Select * from Employee_hierarchy 
    

    如果您想了解公用表表达式或 CTE。这是一个链接 http://technet.microsoft.com/en-us/library/ms186243(v=sql.105).aspx

    【讨论】:

      猜你喜欢
      • 2018-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多