Sql Server 2008 Рекурсивный сохраненный процесс - PullRequest
4 голосов
/ 12 марта 2011

Мне нужно создать хранимую процедуру в SQL Server 2008, которая будет обновлять таблицу на основе некоторого значения.Хитрость в том, что мне нужно рекурсивно искать в таблице, пока не найду нужное значение, а затем обновить текущую запись.Например, у меня есть таблица Employees, которая содержит 3 столбца:

EmployeeId

ManagerId

FamilyId

Для каждого EmployeeId в таблице я хочуполучить его ManagerId.Затем, если ManagerID! = 0, перейдите и получите ManagerId текущего ManagerId (каждый ManagerId будет указывать на EmployeeId) - продолжайте, пока я не доберусь до менеджера верхнего уровня (где ManagerId == 0).

Как только я найду менеджера верхнего уровня, я хочу обновить столбец FamilyId в исходной записи, запустившей процесс, на значение последнего EmployeeId вышеуказанного процесса.

В основном мне нужносделать это с каждой записью в таблице.Я пытаюсь установить для FamilyId значение корневого менеджера для всех сотрудников и менеджеров в иерархии.

Я не уверен, должен ли я использовать курсор или CTE, чтобы сделать это - или просто сделатьэто в коде.

Любая помощь очень ценится.

Спасибо!

Ответы [ 3 ]

5 голосов
/ 12 марта 2011

Вы также можете использовать рекурсивный CTE.

;WITH Hierarchy
     As (SELECT EmployeeId AS _EmployeeId,
                ManagerId  AS _ManagerId,
                EmployeeId AS _FamilyId
         FROM   @Employee
         WHERE  ManagerId = 0
         UNION ALL
         SELECT e.EmployeeId,
                e.ManagerId,
                h._FamilyId
         FROM   @Employee e
                JOIN Hierarchy h
                  ON h._EmployeeId = e.ManagerId)
UPDATE @Employee
SET    FamilyId = _FamilyId
FROM   Hierarchy h
WHERE  EmployeeId = _EmployeeId  
2 голосов
/ 12 марта 2011

Вот мой первый удар.Я надеюсь, что понял ваши требования.

declare @Employee table (
    EmployeeId int not null 
    , ManagerId int not null
    , FamilyId int null
)

--       1       6
--      / \     / \
--     2   3    7 8
--    / \
--    4 5

insert @Employee values (1, 0, null) 
insert @Employee values (2, 1, null) 
insert @Employee values (3, 1, null) 
insert @Employee values (4, 2, null) 
insert @Employee values (5, 2, null) 
insert @Employee values (6, 0, null) 
insert @Employee values (7, 6, null) 
insert @Employee values (8, 6, null) 

-- the data before the update       
select * from @Employee

-- initial update to get immediate managers
update Employee
set FamilyId = Manager.EmployeeId
from @Employee Employee
inner join @Employee Manager on Manager.EmployeeId = Employee.ManagerId

-- the data after the first update     
select * from @Employee

-- do more updates until done
while exists (
    select * 
    from @Employee 
    where (
        FamilyId is not null 
        and FamilyId not in (
            select EmployeeId from @Employee where ManagerId = 0
        )
    )
) 
begin
    update Employee
    set FamilyId = Manager.ManagerId
    from @Employee Employee
    inner join @Employee Manager on Manager.EmployeeId = Employee.FamilyId
    where (
        Employee.FamilyId is not null 
        and Employee.FamilyId not in (
            select EmployeeId from @Employee where ManagerId = 0
        )
    )
end

-- the data after all updates
select * from @Employee

Я уверен, что есть более умные способы

0 голосов
/ 12 марта 2011

Я подозреваю, что для этого я бы вызвал пользовательскую функцию (UDF).UDF будет вызывать себя рекурсивно.

Попробуйте поискать в поиске: рекурсивный сервер UDF sql

Эта ссылка, кажется, дает пример (хотя они и отмечают, что с SQL 2000 выможет пройти только 32 уровня.) http://weblogs.sqlteam.com/jeffs/archive/2003/11/21/588.aspx

Извините, что у меня нет больше времени, чтобы посвятить ваш вопрос прямо сейчас.Если это все еще проблема завтра, я уделю больше времени объяснению.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...