假设我有一个包含以下列的表:
员工表
employeeID int
employeeName varchar(50)
managerID int
totalOrganization int
managerID是对employeeID的引用。对于所有记录,totalOrganization目前为0。
我想将每行的totalOrganization更新为其下的员工总数。
所以有以下记录:
employeeID employeeName managerID totalOrganization
1 John Cruz NULL 0
2 Mark Russell 1 0
3 Alice Johnson 1 0
4 Juan Valdez 3 0
查询应将totalOrganizations更新为:
employeeID employeeName managerID totalOrganization
1 John Cruz NULL 3
2 Mark Russell 1 0
3 Alice Johnson 1 1
4 Juan Valdez 3 0
我知道我可以得到一些组织。图表使用以下CTE:
WITH OrgChart (employeeID, employeeName,managerID,level)
AS (
SELECT employeeID,employeeName,0 as managerID,0 AS Level
FROM Employees
WHERE managerID IS NULL
UNION ALL
SELECT Employees.employeeID,Employees.employeeName,Employees.managerID,Level + 1
FROM Employees INNER JOIN
OrgChart ON Employees.managerID = OrgChart.employeeID
)
SELECT employeeID,employeeName,managerID, level
FROM OrgChart;
有没有办法使用存储过程更新Employees表,而不是在SQL之外构建一些例程来解析数据?
答案 0 :(得分:2)
您可以添加另一个CTE来确定员工数,然后在Update语句中使用它:
WITH OrgChart (employeeID, employeeName,managerID,level)
AS (
SELECT employeeID,employeeName,0 as managerID,0 AS Level
FROM Employees
WHERE managerID IS NULL
UNION ALL
SELECT Employees.employeeID,Employees.employeeName,Employees.managerID,Level + 1
FROM Employees
INNER JOIN OrgChart
ON Employees.managerID = OrgChart.employeeID
)
, SubordinateCount As
(
Select ManagerId, Count(*) As Total
From OrgChart
Group By ManagerId
)
Update Employees
Set TotalOrganization = SubordinateCount.Total
FROM SubordinateCount
Join Employees As E
On E.employeeId = SubordinateCount.ManagerId
<强> ADDITION 强>
规范的变化是您想要计算所有下属员工。这样做的诀窍是为每个经理创建一个员工的路径。所以,首先是我的测试数据:
Insert Employees(EmployeeId, Name, ManagerId) Values(1, 'Alice', Null)
Insert Employees(EmployeeId, Name, ManagerId) Values(2, 'Bob', 1)
Insert Employees(EmployeeId, Name, ManagerId) Values(3, 'Charlie', 1)
Insert Employees(EmployeeId, Name, ManagerId) Values(4, 'Dan', 3)
Insert Employees(EmployeeId, Name, ManagerId) Values(5, 'Ellen', 3)
Insert Employees(EmployeeId, Name, ManagerId) Values(6, 'Fred', 5)
Insert Employees(EmployeeId, Name, ManagerId) Values(7, 'Gale', 6)
Insert Employees(EmployeeId, Name, ManagerId) Values(8, 'Harry', 6)
所以,首先我们编写一个查询,为我们提供他们经理的路径:
With
OrgChart As
(
Select E.EmployeeId, E.Name, Null As ManagerId, 0 AS Level
, Cast( '/' + Cast(E.EmployeeId As varchar(10)) + '/' As varchar(100) ) As Path
From dbo.Employees As E
Where E.ManagerId Is Null
Union All
Select E.EmployeeID, E.Name, E.ManagerID, Level + 1
, Cast( OrgChart.Path + Cast(E.EmployeeId As varchar(10)) + '/' As varchar(100))
From dbo.Employees As E
Join OrgChart
On OrgChart.EmployeeId = E.ManagerID
)
Select *
From OrgChart
产生:
EmployeeId Name ManagerId Level Path
1 Alice NULL 0 /1/
2 Bob 1 1 /1/2/
3 Charlie 1 1 /1/3/
4 Dan 3 2 /1/3/4/
5 Ellen 3 2 /1/3/5/
6 Fred 5 3 /1/3/5/6/
7 Gale 6 4 /1/3/5/6/7/
8 Harry 6 4 /1/3/5/6/8/
现在我们只需要计算给定员工存在于某人路径中的实例:
With
OrgChart As
(
Select E.EmployeeId, E.Name, Null As ManagerId, 0 AS Level
, Cast( '/' + Cast(E.EmployeeId As varchar(10)) + '/' As varchar(100) ) As Path
From dbo.Employees As E
Where E.ManagerId Is Null
Union All
Select E.EmployeeID, E.Name, E.ManagerID, Level + 1
, Cast( OrgChart.Path + Cast(E.EmployeeId As varchar(10)) + '/' As varchar(100))
From dbo.Employees As E
Join OrgChart
On OrgChart.EmployeeId = E.ManagerID
)
, OrgCounts As
(
Select O.EmployeeId, O.Name, O.ManagerId, O.Level, O.Path
, (Select Count(*)
From OrgChart As O1
Where O1.Path Like '%/' + Cast(E.EmployeeId As varchar(10)) + '/%') - 1 As SubordinateTotal
From Employees As E
Join OrgChart As O
On O.EmployeeId = E.EmployeeId
)
Select O.EmployeeId, O.Name, O.ManagerId, O.Level, O.Path, O.SubordinateTotal
From OrgCounts
我从总数中减去一个以排除当前员工。现在我们已经找到了一个提供正确结果的查询,我们可以轻松地使用它来进行更新:
With
OrgChart As
(
Select E.EmployeeId, E.Name, Null As ManagerId, 0 AS Level
, Cast( '/' + Cast(E.EmployeeId As varchar(10)) + '/' As varchar(100) ) As Path
From dbo.Employees As E
Where E.ManagerId Is Null
Union All
Select E.EmployeeID, E.Name, E.ManagerID, Level + 1
, Cast( OrgChart.Path + Cast(E.EmployeeId As varchar(10)) + '/' As varchar(100))
From dbo.Employees As E
Join OrgChart
On OrgChart.EmployeeId = E.ManagerID
)
, OrgCounts As
(
Select O.EmployeeId, O.Name, O.ManagerId, O.Level, O.Path
, (Select Count(*)
From OrgChart As O1
Where O1.Path Like '%/' + Cast(E.EmployeeId As varchar(10)) + '/%') - 1 As SubordinateTotal
From Employees As E
Join OrgChart As O
On O.EmployeeId = E.EmployeeId
)
Update Employees
Set TotalOrganization = O.SubordinateTotal
From OrgCounts As O
Join dbo.Employees As E
On E.EmployeeId = O.EmployeeId
答案 1 :(得分:2)
经过几个小时的实验,我想出了以下内容。它给出了期望的结果。有人看到改善它的方法吗?
CREATE TABLE #totalOrganization (employeeID int,managerID int,level int);
CREATE TABLE #countedOrganization (employeeID int,managerID int,orgCount int,level int);
WITH OrgChart (employeeID,managerID,level)
AS (
SELECT employeeID,0 as managerID,0 AS Level
FROM Emp
WHERE managerID IS NULL
UNION ALL
SELECT Emp.employeeID,Emp.managerID,Level + 1
FROM Emp
INNER JOIN OrgChart
ON Emp.managerID = OrgChart.employeeID
)
INSERT INTO
#totalOrganization
SELECT
employeeID,managerID,level
FROM
OrgChart;
DECLARE @maxLevel int
SELECT
@maxLevel = MAX(level)
FROM
#totalOrganization;
WHILE (@maxLevel > -1)
BEGIN
INSERT INTO
#countedOrganization
SELECT
upline.employeeID,upline.managerID,SUM(CONVERT(INT,CASE WHEN downline.orgCount IS NULL THEN 0 ELSE downline.orgCount END)) + CONVERT(INT,CASE WHEN COUNT(downline.employeeID) IS NULL THEN 0 ELSE COUNT(downline.employeeID) END),upline.level
FROM
#totalOrganization AS upline LEFT OUTER JOIN
#countedOrganization AS downline ON downline.managerID=upline.employeeID
WHERE
upline.level = @maxLevel
GROUP BY
upline.employeeID,upline.managerID,upline.level
SET @maxLevel = @maxLevel - 1
END
UPDATE
Emp
SET
totalOrg= CONVERT(INT,CASE WHEN orgCount IS NULL THEN 0 ELSE orgCount END)
FROM
#countedOrganization INNER JOIN
Emp ON #countedOrganization.employeeID=Emp.employeeID
答案 2 :(得分:0)
这可以(当然)在存储过程中完成。但是,它看起来非常像单个(CTE)语句无法完成,因为您无法对给定员工的下属及其所有下属进行求和(即,计算所有后代在给定项目下面层次结构),根据此错误消息:
GROUP BY, HAVING, or aggregate functions are not allowed in the recursive part of a recursive common table expression 'Subordinates'.
因此,您在SQL之外编写的例程(从层次结构的最低“级别开始,计算所有下级员工,在迭代层次结构时重复)将必须在SQL中编写。