我已经看到了几个关于如何递归查询自引用表的问题/答案,但我正在努力应用我发现的答案来汇总到每个 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
在哪里:
人事部工资
最佳答案
样本数据
我添加了几行具有更宽树结构的行。
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/