2013-05-21 57 views
3

我不知道什麼最好的方法是獲得我要找的結果。在一個oracle 10g數據庫中,我試圖查詢所有用戶,併爲每個有主管人員的行生成一個計算字段,如果他們的主管類型是U.如果不是,我需要走到樹上直到找到一個。這個查詢可能需要遞增多個級別。我需要一個遞歸查詢來獲得在oracle中的計算字段

所以對於一個Employee表是這樣的:

Employee Table 
+-------+----------+--------------+---------------+ 
| empno | empgroup |  user  | supervisor_no | 
+-------+----------+--------------+---------------+ 
|  1 | E  | Joe Schmo |    4 | 
|  2 | E  | Mark Marin |    3 | 
|  3 | U  | Reed Patter |    7 | 
|  4 | E  | Martin Price |    7 | 
|  7 | U  | Mary Wengert |    | 
+-------+----------+--------------+---------------+ 

我希望看到這樣的結果,其中manager_no將計算出的字段

Results 
+-------+----------+--------------+---------------+------------+ 
| empno | empgroup |  user  | supervisor_no | Manager_No | 
+-------+----------+--------------+---------------+------------+ 
|  1 | E  | Joe Schmo |    4 |   7 | 
|  2 | E  | Mark Marin |    3 |   3 | 
|  3 | U  | Reed Patter |    7 |   7 | 
|  4 | E  | Martin Price |    7 |   7 | 
|  7 | U  | Mary Wengert |    |   | 
+-------+----------+--------------+---------------+------------+ 

好了,所以我一直在問我試過。我並不是說這是必須這樣做的方式,如果有人有更好的建議,我全都是耳朵,但這是我想要實現的。

我想象了兩部分。

select * from employee em 
connect by prior supervisor_no = empno 
start with empno = 1 

[結果] [2]:即得到所有我的結果

select em.empno, em.empgroup, em.user, em.supervisor, (my subquery) as manager_no 
from employee em 

查詢主查詢

| EMPNO | EMPGROUP |  USERNAME | SUPERVISOR_NO | 
--------------------------------------------------- 
|  1 |  E | Joe Schmo |    4 | 
|  4 |  E | Martin Price |    7 | 
|  7 |  U | Mary Wengert |  (null) | 

好吧,我找到了一種方法來篩選對可能工作的團隊,但不知道這是否是最有效的路線。

SELECT empno FROM (
SELECT empno FROM employee em 
CONNECT BY PRIOR supervisor_no = empno 
START WITH empno = 1 
order by level) d 
WHERE d.empgroup = 'U' and rownum =1 

我也創建了一個小提琴,如果有幫助。 http://www.sqlfiddle.com/#!4/c8805/4

+0

公平問題。我不確定這是否是我需要的,但我確實需要不斷詢問每個人的主管,直到獲得符合我標準的人員。我會在我能儘快嘗試的問題上添加更多信息。謝謝。 – Josh

+0

爲你的SQL小提琴+1。 – jpmc26

回答

2

那麼,你的問題變得對我是個挑戰,但我沒有放棄,並得到這個只用SQL和內置函數(不應該慢慢地工作,而且相當可轉位需要):

select distinct 
    empno, 
    empgroup, 
    username, 
    supervisor_no, 
    manager_no 
from (
    select 
      e.*, 
      decode(
     instr(
      sys_connect_by_path(empgroup, '/'), 
      'U/', 
      -1 
     ), 
     0, 
     null, 
     substr(
      sys_connect_by_path(empno, '/'), 
      instr(
       sys_connect_by_path(empno, '/'), 
       '/', 
       1, 
       length(
        substr(
         sys_connect_by_path(empgroup, '/'), 
         1, 
         instr(
          sys_connect_by_path(empgroup, '/'), 
          'U/', 
          -1 
         ) 
        ) 
       ) - length(
        replace(
         substr(
          sys_connect_by_path(empgroup, '/'), 
          1, 
          instr(
           sys_connect_by_path(empgroup, '/'), 
           'U/', 
           -1 
          ) 
         ), 
         '/' 
        ) 
       ) 
      ) + 1, 
      instr(
       sys_connect_by_path(empno, '/'), 
       '/', 
       1, 
       length(
        substr(
         sys_connect_by_path(empgroup, '/'), 
         1, 
         instr(
          sys_connect_by_path(empgroup, '/'), 
          'U/', 
          -1 
         ) 
        ) 
       ) - length(
        replace(
         substr(
          sys_connect_by_path(empgroup, '/'), 
          1, 
          instr(
           sys_connect_by_path(empgroup, '/'), 
           'U/', 
           -1 
          ) 
              ), 
               '/' 
             ) 
           ) + 1 
         ) - instr(
           sys_connect_by_path(empno, '/'), 
           '/', 
           1, 
           length(
             substr(
               sys_connect_by_path(empgroup, '/'), 
               1, 
               instr(
                 sys_connect_by_path(empgroup, '/'), 
                 'U/', 
                 -1 
               ) 
             ) 
           ) - length(
             replace(
               substr(
                 sys_connect_by_path(empgroup, '/'), 
                 1, 
                 instr(
                   sys_connect_by_path(empgroup, '/'), 
                   'U/', 
                   -1 
                 ) 
               ), 
               '/' 
             ) 
           ) 
         ) - 1 
       ) 
     ) manager_no 
    from employee e 
    connect by prior empno = supervisor_no 
) 
where manager_no is not null or supervisor_no is null 
order by empno; 

的SQL搗鼓查詢:http://www.sqlfiddle.com/#!4/c8805/27/0

UPDATE: 當我早上起牀,我意識到一切都可以做更容易和查詢變得更具可讀性,在這裏你去:

select 
    empno, 
    empgroup, 
    username, 
    supervisor_no, 
    null manager_no 
from 
    employee 
where 
    supervisor_no is null 
union all 
select 
    empno, 
    empgroup, 
    username, 
    supervisor_no, 
    substr(ep, 2, instr(ep, '/', 2)-2) manager_no 
from (
    select 
    sys_connect_by_path(empgroup, '/') gp, 
    sys_connect_by_path(empno, '/') ep, 
    e.* 
    from employee e 
    connect by prior empno = supervisor_no 
) e 
where 
    substr(gp, 1, 3) = '/U/' 
    and (length(gp) - length(replace(gp, 'U/'))) = length('U/') 
order by empno; 

它的工作原理!以及上面的查詢。SQL小提琴吧:http://www.sqlfiddle.com/#!4/c8805/54/0

享受!

+0

Yahoo,針對所需組的每個名稱以及員工的任何ID長度完成。多麼迷人的任務!試圖正確地爲您設置格式,以便消除它的含義。現在回到工作.. – ZZa

+1

你認爲你可以總結這是做什麼?我很難看這個,但結果看起來不錯。 – Josh

+0

訣竅是使用函數'sys_connect_by_path',它爲您提供從根節點到節點的路徑字符串。因此,在得到它之後,我分析給出的'sys_connect_by_path(empgroup,'/')'的字符串,在這個級別上我首先遇到'U /'(它表示最近的父代不是'E'),然後嘗試從'sys_connect_by_path(empno,'/')'中的相同級別提取必要的ID。所以,主要是使用字符串。 – ZZa

0

也許創建一個遞歸函數來獲取用戶的'U'型監督員?

CREATE OR REPLACE FUNCTION GET_U_SUPERVISOR(employee_no INT) 
RETURN INT IS 
    supervisor_empno INT; 
    supervisor_group VARCHAR(20); 
BEGIN 
    SELECT empno, empgroup 
    INTO supervisor_empno, supervisor_group 
    FROM employee 
    WHERE employee.empno = (SELECT supervisor_no FROM employee WHERE empno = employee_no); 

    IF 'U' = supervisor_group 
    THEN 
     RETURN supervisor_empno; 
    ELSE 
     RETURN GET_U_SUPERVISOR(supervisor_empno); 
    END IF; 
END GET_U_SUPERVISOR; 
/

然後:

SELECT empno, empgroup, username, supervisor_no, GET_U_SUPERVISOR(empno) 
FROM employee; 

一個SQL小提琴回你:http://www.sqlfiddle.com/#!4/c7540/1/0

我不能保證在任何的表現,不過,如果它是一個大桌子。它是遞歸的,並將在每行的基礎上調用。

+0

哦,天哪,遞歸地工作PL/SQL函數..對於這樣一個任務,只是一個資源殺手,老兄! – ZZa

+0

我很感激你花時間做這個,但我想避免創建自定義函數,因爲我沒有權利在我正在使用的數據庫。 – Josh

+0

哦,甲骨文。我如何討厭你的權限。 @ ZZa我從未承諾過高性能。我甚至警告過它。但有時候,你並不需要高性能。 OP沒有給我們說明數據的大小。我只是試圖給出一個工作解決方案。我發現downvote沒有要求。 – jpmc26

-1

我遞歸,SQL Fiddle使用,

CREATE TABLE EMPLOYEE(NO INT, EMP_GROUP VARCHAR2(1), EUSER VARCHAR2(30), SUPERVISOR_NO INT); 

INSERT INTO EMPLOYEE VALUES(1, 'E', 'JOE SCHMO', 4); 
INSERT INTO EMPLOYEE VALUES(2, 'E', 'Mark Marin', 3); 
INSERT INTO EMPLOYEE VALUES(3, 'U', 'Reed Patter', 7); 
INSERT INTO EMPLOYEE VALUES(4, 'E', 'Martin Price ', 7); 
INSERT INTO EMPLOYEE(NO, EMP_GROUP, EUSER) VALUES(7, 'U', 'Mary Wengert'); 
WITH A(EMPLOYEE, MANAGER) AS 
(
    SELECT NO AS EMPLOYEE, SUPERVISOR_NO AS MANAGER FROM EMPLOYEE 
    UNION ALL 
    SELECT A.EMPLOYEE, E.SUPERVISOR_NO AS MANAGER 
    FROM A, EMPLOYEE E 
    WHERE A.MANAGER = E.NO 
    AND E.SUPERVISOR_NO IS NOT NULL 
) 

SELECT * FROM A 
ORDER BY 1 
+0

您的查詢會產生兩個錯誤結果的額外行。在你的SQL小提琴上,第一行將員工'1'映射到主管'4'(他不是'U''管理員),最後一行將員工'2'映射到主管'7'(誰不是'2'下的最低等級'U'型經理)。 – jpmc26

+0

即使它工作正常,想象一下,如果最近的經理是3-4級更深。 – ZZa

+0

是的。但我用遞歸來證明我們可以找到immidiate主管。 – Santhosh