0

假设我有一个包含以下列的表格:

员工

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;

有没有办法使用存储过程更新雇员表,而不是在 SQL 之外构建一些例程来解析数据?

4

3 回答 3

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

添加

规格的变化是您想要计算所有下属员工。诀窍是为员工创建通往每位经理的路径。所以,首先这是我的测试数据:

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
于 2010-06-07T21:43:24.853 回答
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
于 2010-06-08T00:48:17.900 回答
0

这可以(当然)在存储过程中完成。但是,它看起来很像不能用单个 (CTE) 语句来完成,因为您不能根据这个错误总结给定员工的下属 + 他们的所有下属(即统计层次结构中给定项目下的所有后代)信息:

GROUP BY, HAVING, or aggregate functions are not allowed in the recursive part of a recursive common table expression 'Subordinates'.

因此,您在 SQL 之外编写的例程(从层次结构的最低“级别”开始,计算所有这些员工的下属,在迭代层次结构时重复)必须在 SQL 中编写。

于 2010-06-07T22:11:13.100 回答