我已经看到了几个关于如何递归查询自引用表的问题/答案,但我正在努力应用我发现的答案来汇总到每个 parent 、祖 parent 等。无论项目位于等级制度。

需要获得每个部门的平均工资,包括层次结构。
这意味着部门应该包括每个子部门的平均工资等等。

我有 nex db 架构:

CREATE TABLE Employee
    (
      Id INT NOT NULL ,
      Name VARCHAR(200) NOT NULL ,
      Department_Id INT NOT NULL ,
      PRIMARY KEY ( Id )
    );

CREATE TABLE Department
    (
      Id INT NOT NULL ,
      DepartmentName VARCHAR(200) NOT NULL ,
      Parent_Id INT ,
      PRIMARY KEY ( Id )
    );

CREATE TABLE Salary
    (
      Id INT NOT NULL ,
      Date DATETIME NOT NULL ,
      Amount INT NOT NULL ,
      Employee_Id INT NOT NULL ,
      PRIMARY KEY ( Id )
    );

我试过类似的东西,但它只包含层次结构的第一级。
SELECT  d.Id ,
        d.DepartmentName ,
        ( SELECT    AVG(s.Amount)
                FROM      dbo.Department dd
                        LEFT JOIN dbo.Department sdd ON dd.Id = sdd.Parent_Id
                        JOIN dbo.Employee e ON e.Department_Id = sdd.Id
                                                OR e.Department_Id = dd.Id
                        JOIN dbo.Salary s ON s.Employee_Id = e.Id
                                                WHERE dd.Id = d.Id
        ) AS avg_dep_salary
FROM    dbo.Department d
WHERE   d.Parent_Id IS NULL;

怎样才能拿到各个级别的平均工资?

编辑: 添加了一些插入
INSERT  INTO Employee
        ( Id, Name, Department_Id )
VALUES  ( 1, 'Peter', 1 ),
        ( 2, 'Alex', 1 ),
        ( 3, 'Sam', 2 ),
        ( 4, 'James', 2 ),
        ( 5, 'Anna', 3 ),
        ( 6, 'Susan', 3 ),
        ( 7, 'Abby', 4 ),
        ( 8, 'Endy', 4 );

INSERT  INTO Department
        ( Id, DepartmentName, Parent_Id )
VALUES  ( 1, 'IT', NULL ),
        ( 2, 'HR', NULL),
        ( 3, 'SubIT', 1 ),
        ( 4, 'SubSubIT', 3 );

INSERT  INTO Salary
        ( Id, Date, Amount, Employee_Id )
VALUES  ( 1, '2013-01-09 16:03:50.003', 3000, 1 ),
        ( 2, '2013-01-11 16:03:50.003', 5000, 2 ),
        ( 3, '2013-01-09 16:03:50.003', 2000, 3 ),
        ( 4, '2013-01-11 16:03:50.003', 1000, 4 ),
        ( 5, '2013-01-09 16:03:50.003', 4000, 5 ),
        ( 6, '2013-01-11 16:03:50.003', 6000, 6 ),
        ( 7, '2013-01-09 16:03:50.003', 7000, 7 ),
        ( 8, '2013-01-13 16:03:50.003', 9000, 8 );

预期结果是:
Department | Average_Salary
__________________________________
IT         |  ( X1 + X2 + X3 ) / 3
HR         |  ( Y1 ) / 1
SubIT      |  ( X2 + X3 ) / 2
SubSubIT   |  ( X3 ) / 1

在哪里:
  • X1 - IT 部门的平均工资
  • X2 - SubIT 部门的平均工资
  • X3 - SubSubIT 部门的平均工资
  • Y1 - 平均值
    人事部工资
  • 最佳答案

    样本数据

    我添加了几行具有更宽树结构的行。

    DECLARE @Employee TABLE
    (
    Id INT NOT NULL ,
    Name VARCHAR(200) NOT NULL ,
    Department_Id INT NOT NULL ,
    PRIMARY KEY ( Id )
    );
    
    DECLARE @Department TABLE
    (
    Id INT NOT NULL ,
    DepartmentName VARCHAR(200) NOT NULL ,
    Parent_Id INT ,
    PRIMARY KEY ( Id )
    );
    
    DECLARE @Salary TABLE
    (
    Id INT NOT NULL ,
    Date DATETIME NOT NULL ,
    Amount INT NOT NULL ,
    Employee_Id INT NOT NULL ,
    PRIMARY KEY ( Id )
    );
    
    INSERT  INTO @Employee
    ( Id, Name, Department_Id )
    VALUES
    ( 1, 'Peter', 1 ),
    ( 2, 'Alex',  1 ),
    ( 3, 'Sam',   2 ),
    ( 4, 'James', 2 ),
    ( 5, 'Anna',  3 ),
    ( 6, 'Susan', 3 ),
    ( 7, 'Abby',  4 ),
    ( 8, 'Endy',  4 ),
    (10, 'e_A',   10),
    (11, 'e_AB',  11),
    (12, 'e_AC',  12),
    (13, 'e_AD',  13),
    (14, 'e_ACE', 14),
    (15, 'e_ACF', 15),
    (16, 'e_ACG', 16);
    
    INSERT  INTO @Department
    ( Id, DepartmentName, Parent_Id )
    VALUES
    ( 1, 'IT', NULL ),
    ( 2, 'HR', NULL),
    ( 3, 'SubIT', 1 ),
    ( 4, 'SubSubIT', 3 ),
    (10, 'A', NULL ),
    (11, 'AB', 10),
    (12, 'AC', 10),
    (13, 'AD', 10),
    (14, 'ACE', 12),
    (15, 'ACF', 12),
    (16, 'ACG', 12);
    
    INSERT  INTO @Salary
    ( Id, Date, Amount, Employee_Id )
    VALUES
    ( 1, '2013-01-09 16:03:50.003', 3000, 1 ),
    ( 2, '2013-01-11 16:03:50.003', 5000, 2 ),
    ( 3, '2013-01-09 16:03:50.003', 2000, 3 ),
    ( 4, '2013-01-11 16:03:50.003', 1000, 4 ),
    ( 5, '2013-01-09 16:03:50.003', 4000, 5 ),
    ( 6, '2013-01-11 16:03:50.003', 6000, 6 ),
    ( 7, '2013-01-09 16:03:50.003', 7000, 7 ),
    ( 8, '2013-01-13 16:03:50.003', 9000, 8 ),
    (10, '2013-01-13 16:03:50', 100, 10),
    (11, '2013-01-13 16:03:50', 100, 11),
    (12, '2013-01-13 16:03:50', 100, 12),
    (13, '2013-01-13 16:03:50', 100, 13),
    (14, '2013-01-13 16:03:50', 100, 14),
    (15, '2013-01-13 16:03:50', 100, 15),
    (16, '2013-01-13 16:03:50', 100, 16);
    

    查询
    WITH
    CTE_Departments
    AS
    (
        SELECT
            D.Id
            ,D.Parent_Id
            ,D.DepartmentName
            ,SUM(Amount) AS DepartmentAmount
            ,COUNT(*) AS DepartmentCount
        FROM
            @Department AS D
            INNER JOIN @Employee AS E ON E.Department_Id = D.Id
            INNER JOIN @Salary AS S ON S.Employee_Id = E.Id
        GROUP BY
            D.Id
            ,D.Parent_Id
            ,D.DepartmentName
    )
    ,CTE_Recursive
    AS
    (
        SELECT
             CTE_Departments.Id AS OriginalID
            ,CTE_Departments.DepartmentName AS OriginalName
            ,CTE_Departments.Id
            ,CTE_Departments.Parent_Id
            ,CTE_Departments.DepartmentName
            ,CTE_Departments.DepartmentAmount
            ,CTE_Departments.DepartmentCount
            ,1 AS Lvl
        FROM CTE_Departments
    
        UNION ALL
    
        SELECT
             CTE_Recursive.OriginalID
            ,CTE_Recursive.OriginalName
            ,CTE_Departments.Id
            ,CTE_Departments.Parent_Id
            ,CTE_Departments.DepartmentName
            ,CTE_Departments.DepartmentAmount
            ,CTE_Departments.DepartmentCount
            ,CTE_Recursive.Lvl + 1 AS Lvl
        FROM
            CTE_Departments
            INNER JOIN CTE_Recursive ON CTE_Recursive.Id = CTE_Departments.Parent_Id
    )
    SELECT
        OriginalID
        ,OriginalName
        ,SUM(DepartmentAmount) AS SumAmount
        ,SUM(DepartmentCount) AS SumCount
        ,SUM(DepartmentAmount) / SUM(DepartmentCount) AS AvgAmount
    FROM CTE_Recursive
    GROUP BY
        OriginalID
        ,OriginalName
    ORDER BY OriginalID
    ;
    

    结果
    +------------+--------------+-----------+----------+-----------+
    | OriginalID | OriginalName | SumAmount | SumCount | AvgAmount |
    +------------+--------------+-----------+----------+-----------+
    |          1 | IT           |     34000 |        6 |      5666 |
    |          2 | HR           |      3000 |        2 |      1500 |
    |          3 | SubIT        |     26000 |        4 |      6500 |
    |          4 | SubSubIT     |     16000 |        2 |      8000 |
    |         10 | A            |       700 |        7 |       100 |
    |         11 | AB           |       100 |        1 |       100 |
    |         12 | AC           |       400 |        4 |       100 |
    |         13 | AD           |       100 |        1 |       100 |
    |         14 | ACE          |       100 |        1 |       100 |
    |         15 | ACF          |       100 |        1 |       100 |
    |         16 | ACG          |       100 |        1 |       100 |
    +------------+--------------+-----------+----------+-----------+
    

    逐步运行查询,逐个 CTE 以了解其工作原理。
    CTE_Departments 给出每个部门的总人数和人数。
    CTE_Recursive 为每个部门递归生成子行,同时保留 OriginalID - 递归开始的部门的 ID。

    最终查询只是按此 OriginalID 对所有内容进行分组。

    关于sql在自我引用表中获取平均工资,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48773468/

    10-16 11:19