2011-03-12 123 views
4

我需要在SQL Server 2008中創建一個存儲過程,它將根據某個值更新一個表。這裏的技巧是我需要遞歸搜索表,直到找到我正在查找的值,然後更新當前記錄。例如,我有一個包含3列的僱員表:Sql Server 2008遞歸存儲過程

僱員

經理ID

FAMILYID

對於表中的每一個僱員,我想它的經理ID。然後,如果ManagerID!= 0,則獲取當前ManagerId的ManagerId(每個ManagerId將指向一個EmployeeId) - 繼續執行此操作,直到我到達頂級管理器(其中ManagerId == 0)。

一旦我找到最高級別的管理器,我想更新原始記錄中啓動該進程的FamilyId列,並使用上述進程的最後一個EmployeeId的值。

基本上我需要對錶中的每條記錄進行此操作。我嘗試將FamilyId設置爲層次結構中所有員工和管理員的根管理器的值。

我不確定是否應該使用遊標或CTE來完成此操作 - 或者只是在代碼中執行此操作。

任何幫助,非常感謝。

謝謝!

+0

你應該張貼在stackexchange這個問題[DBA專家現場](http://dba.stackexchange.com/) – CoderHawk 2011-03-12 04:46:17

+0

@Sandy - 這是編程的問題不是關於數據庫的管理問題。 – 2011-03-12 12:50:16

+0

從你的描述中可以看出,'FamilyId'對任意'根'員工的所有'下屬'來說都是一樣的嗎?如果是這樣,爲什麼總是去樹頂? – 2011-03-12 13:03:08

回答

5

你也可以使用遞歸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 
+1

+1,絕對。我只是自己去做。給了我麻煩,謝謝。 :)遞歸CTE似乎只是出於任務。 – 2011-03-12 13:07:21

+0

@Andriy - 恥辱,它不允許遞歸CTE本身是可更新的,所以它需要回到原來的表上雖然(除非有這樣做的某種方式?) – 2011-03-12 13:10:14

+0

@馬丁:不會肯定地說,但我懷疑是否有這種方式。鑑於CTE正在從多個表中讀取數據,引擎很難決定哪張表應該更新。 – 2011-03-12 13:14:19

0

我懷疑我會爲此調用一個用戶定義的函數(UDF)。 UDF將遞歸地調用它自己。

嘗試google搜索:遞歸UDF的SQL Server

此鏈接似乎舉個例子(儘管他們確實注意到,由於SQL 2000的,你只能遞歸32級深。) http://weblogs.sqlteam.com/jeffs/archive/2003/11/21/588.aspx

對不起,我現在沒有更多時間專注於您的問題。如果明天仍然是個問題,我會花更多的時間來解釋。

2

這是我的第一次刺傷它。我希望我瞭解你的要求。

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

...特別是,如果您使用的是SQL 2008的HierarchyId,我相信您可以在一行中完成此操作! – anon 2011-03-12 05:09:01

+0

+1恰好格式化的答案,我借用了你的餐桌人口代碼! – 2011-03-12 19:04:43

+0

@Martin - +1右後方CTE解決方案atcha和教我一個新術語:「萬聖節保護」=) – anon 2011-03-13 00:50:18