【问题标题】:How to query and parse adjacent list hierarchy using cte?如何使用 cte 查询和解析相邻列表层次结构?
【发布时间】:2012-10-31 22:21:19
【问题描述】:

如何查询此父子层次结构以生成其中级别位于其自己的列中的结果集?样本数据:

SET NOCOUNT ON;
USE Tempdb;

IF OBJECT_ID('dbo.Employees', 'U') IS NOT NULL DROP TABLE dbo.Employees;

CREATE TABLE dbo.Employees
(
  empid   INT         NOT NULL PRIMARY KEY,
  mgrid   INT         NULL     REFERENCES dbo.Employees,
  empname VARCHAR(25) NOT NULL,
  salary  MONEY       NOT NULL,
  CHECK (empid <> mgrid),
  CHECK (empid > 0)
);

CREATE UNIQUE INDEX idx_unc_mgrid_empid ON dbo.Employees(mgrid, empid);

INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES
  (1,  NULL, 'David'  , $10000.00),
  (2,  1,    'Eitan'  ,  $7000.00),
  (3,  1,    'Ina'    ,  $7500.00),
  (4,  2,    'Seraph' ,  $5000.00),
  (5,  2,    'Jiru'   ,  $5500.00),
  (6,  2,    'Steve'  ,  $4500.00),
  (7,  3,    'Aaron'  ,  $5000.00),
  (8,  5,    'Lilach' ,  $3500.00),
  (9,  7,    'Rita'   ,  $3000.00),
  (10, 5,    'Sean'   ,  $3000.00),
  (11, 7,    'Gabriel',  $3000.00),
  (12, 9,    'Emilia' ,  $2000.00),
  (13, 9,    'Michael',  $2000.00),
  (14, 9,    'Didi'   ,  $1500.00);

select * from dbo.Employees
go     

;WITH Tree (empid, mgrid, lv)
AS (

SELECT empid, mgrid, 1
FROM Employees
WHERE mgrid IS NULL 

UNION ALL

SELECT E.empid, E.mgrid, lv + 1
FROM Employees AS E
JOIN Tree
ON E.mgrid= Tree.empid
)
SELECT empid, mgrid, lv
FROM Tree
ORDER BY Lv, empid

生成的表应该具有类似的结构

+-------+-----+--------+--------+--------+--------+--------+
| empid | lvl | level1 | level2 | level3 | level4 | level5 |
+-------+-----+--------+--------+--------+--------+--------+
|     1 |   1 |      1 | NULL   | NULL   | NULL   | NULL   |
|     2 |   2 |      1 | 2      | NULL   | NULL   | NULL   |
|     3 |   2 |      1 | 3      | NULL   | NULL   | NULL   |
|     4 |   3 |      1 | 2      | 4      | NULL   | NULL   |
|     5 |   3 |      1 | 2      | 5      | NULL   | NULL   |
|     6 |   3 |      1 | 2      | 6      | NULL   | NULL   |
|     7 |   3 |      1 | 3      | 7      | NULL   | NULL   |
|     8 |   4 |      1 | 2      | 5      | 8      | NULL   |
|     9 |   4 |      1 | 3      | 7      | 9      | NULL   |
|    10 |   4 |      1 | 2      | 5      | 10     | NULL   |
|    11 |   4 |      1 | 3      | 7      | 11     | NULL   |
|    12 |   5 |      1 | 3      | 7      | 9      | 12     |
|    13 |   5 |      1 | 3      | 7      | 9      | 13     |
|    14 |   5 |      1 | 3      | 7      | 9      | 14     |
+-------+-----+--------+--------+--------+--------+--------+

【问题讨论】:

  • 您没有明确说明 level1..level5 列中的内容。您能否使用示例输入数据给出示例结果集? [另外,你知道你只需要5个级别吗?]
  • 是的,我知道,我只需要前 5 个级别。

标签: sql sql-server sql-server-2008 tsql hierarchy


【解决方案1】:

您的示例数据使问题更加清晰。您可以在下降时收集经理级别:

; with  Tree as
        (
        SELECT  empid
        ,       mgrid
        ,       1 as lv
        ,       1 as level1
        ,       null as level2
        ,       null as level3
        ,       null as level4
        ,       null as level5
        FROM    Employees
        WHERE   mgrid IS NULL 
        UNION ALL
        SELECT  E.empid
        ,       E.mgrid
        ,       T.lv + 1
        ,       T.level1
        ,       case when T.lv = 1 then E.empid else t.level2 end
        ,       case when T.lv = 2 then E.empid else t.level3 end
        ,       case when T.lv = 3 then E.empid else t.level4 end
        ,       case when T.lv = 4 then E.empid else t.level5 end
        FROM    Employees AS E
        JOIN    Tree T
        ON      E.mgrid = T.empid
        )
select  *
from    Tree

Example at SQL Fiddle.

【讨论】:

  • @jrara:你说得对,关系颠倒了。新版本应该会更好:#12 报告到 9、9 到 7、7 到 3、3 到 1。
  • @jrara:这解释了你在寻找什么,回答更新
  • @Dems:看起来是这样,您的答案在我的 SQL 小提琴中有效,并修复了一些错字
【解决方案2】:
;WITH Tree (empid, level, level1, level2, level3, level4, level5)
AS (

SELECT empid, 1, empid, NULL, NULL, NULL, NULL
FROM Employees
WHERE mgrid IS NULL 

UNION ALL

SELECT E.empid, T.level + 1,
       CASE WHEN T.level+1 = 1 THEN E.empid ELSE T.level1 END,
       CASE WHEN T.level+1 = 2 THEN E.empid ELSE T.level2 END,
       CASE WHEN T.level+1 = 3 THEN E.empid ELSE T.level3 END,
       CASE WHEN T.level+1 = 4 THEN E.empid ELSE T.level4 END,
       CASE WHEN T.level+1 = 5 THEN E.empid ELSE T.level5 END 
FROM Employees AS E
JOIN Tree T
ON E.mgrid= T.empid
)
SELECT empid, level, level1, level2, level3, level4, level5
FROM Tree

【讨论】:

    【解决方案3】:

    有支点?

    ;WITH Tree (empid, mgrid, lv)
    AS (
    
    SELECT empid, mgrid, 1
    FROM @Employees
    WHERE mgrid IS NULL 
    
    UNION ALL
    
    SELECT E.empid, E.mgrid, lv + 1
    FROM @Employees AS E
    JOIN Tree
    ON E.mgrid= Tree.empid
    )
    select *
    from
    Tree
    pivot 
    (count(empid) for lv in ([1],[2],[3],[4],[5]))p
    

    【讨论】:

    • 那么什么是正确的结果集?您的网格中的数字是如何计算的?
    猜你喜欢
    • 2012-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-03
    • 2014-09-28
    • 2013-03-18
    相关资源
    最近更新 更多