2013-12-12 21 views
2

我需要下列表格中管理員使用MYSQL的層次結構後所有員工的列表。在oracle或mssql中很容易,但在MySQL中找不到任何解決方案。任何人都可以幫我解決這個問題。使用mysql管理器下的員工遞歸計數

id name manager 

1 John 6 
2 Gill 7 
3 Ben  2 
4 Roy  8 
5 Lenin 6 
6 Nancy 7 
7 Sam  0 
8 Dolly 3 
+0

對管理層次結構的深度有多大限制? –

+1

不,沒有最大限制 – Swadesh

+1

正如你所看到的,在MySQL中沒有遞歸,所以選項包括 - 根據需要經常加入表格 - 編寫一個sproc(如下所示) - 切換到嵌套集合模型,或者 - 在應用程序級別處理遞歸,例如與一點PHP。另外,按照慣例,我們使用NULL而不是0來表示孤兒。 – Strawberry

回答

3

如果你仍然可以限制最大級別的數量,這是一個遞歸過程的解決方案。由於遞歸函數在MySQL中是不允許的,我們在這裏有一個函數(manager_count),它包含了遞歸過程的結果。遞歸深度由max_sp_recursion_depth變量控制,該變量爲takes 255 as its maximum。使用方法如下:SELECT *,manager_count(id) FROM my_table。這不是最佳的解決方案,因爲它沒有考慮到層次結構的已計數分支(臨時表實際上可以用作緩存)。

DELIMITER // 
DROP FUNCTION IF EXISTS manager_count// 
CREATE FUNCTION manager_count(_manager INT) RETURNS INT 
BEGIN 
    DECLARE _count INT DEFAULT 0; 
    SET max_sp_recursion_depth = 255; 
    # manager_count_helper does the job 
    CALL manager_count_helper(_manager, _count); 
    # subtract 1, because manager_count_helper will count this manager as well 
    RETURN _count - 1; 
END// 

DROP PROCEDURE IF EXISTS manager_count_helper// 
CREATE PROCEDURE manager_count_helper(IN _manager INT, INOUT _count INT) 
BEGIN 
    IF EXISTS (SELECT 1 FROM my_table WHERE id = _manager) THEN 
    BEGIN 
     DECLARE _next_manager INT DEFAULT 0; 
     DECLARE done BOOLEAN DEFAULT FALSE; 
     # cursor to loop through the employees 
     DECLARE _cursor CURSOR FOR SELECT id FROM my_table WHERE manager = _manager; 
     # if done, the done variable gets TRUE and it's time too leave 
     DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; 
     # count 1, because this guy should be counted as well 
     SET _count = _count + 1; 
     OPEN _cursor; 
     read_loop: LOOP 
      FETCH _cursor INTO _next_manager; 
      IF done THEN LEAVE read_loop; 
      END IF; 
      CALL manager_count_helper(_next_manager, _count); 
     END LOOP; 
     CLOSE _cursor; 
    END; 
    END IF; 
END 
+0

動態使用的另一種方法是創建另一個帶有計數的表並通過主表上的觸發器進行管理(您需要使用其他函數來查找父母記錄以添加/減少計數)。第一步仍然是'CREATE TABLE my_counts SELECT id,manager_count(id)as manager_counts FROM my_table'。 –