3

我不确定获得所需结果的最佳方法是什么。在 oracle 10g 数据库中,我试图查询所有用户并为每行生成一个计算字段,如果他们的主管类型是 U。如果不是,我需要沿着树向上走,直到找到一个. 此查询可能需要递归多个级别。

所以对于这样的 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 em.empno, em.empgroup, em.user, em.supervisor, (my subquery) as manager_no
from employee em

查询

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

[结果][2]

| 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

4

3 回答 3

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 Fiddle:http ://www.sqlfiddle.com/#!4/c8805/27/0

更新: 当我早上起床时,我意识到一切都可以更轻松地完成,并且查询变得更具可读性,你去:

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 Fiddle:http ://www.sqlfiddle.com/#!4/c8805/54/0

享受!

于 2013-05-22T06:31:06.883 回答
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 Fiddle 回到你身边:http ://www.sqlfiddle.com/#!4/c7540/1/0

不过,如果它是一张大桌子,我不能保证在这方面有任何表现。它是递归的,将在每行的基础上调用。

于 2013-05-22T00:10:31.210 回答
-1

我使用 WITH recursive,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
于 2013-05-23T06:31:34.383 回答