分层查询-每级限制元素数量

时间:2018-11-21 23:39:03

标签: sql oracle oracle11g hierarchy

我正在使用Oracle DBMS,但我对分层查询有疑问。

我正在使用分层SQL查询为工作中的部门创建组织列表。组织结构分为三个级别,分别是部门经理,部门经理和团队成员。

到目前为止,我的查询是:

SELECT level, employee_number, name, manager, department, phone
FROM employee_table
START WITH manager is null
CONNECT BY PRIOR employee_number = manager;

此查询将生成一个层次结构列表,其中部门经理处于第一级,每个部门经理处于第二级,团队成员处于第三级。总体而言,只有一名部门经理,三名部门经理和30名团队成员。

问题:我的要求是将列表中每个级别的员工人数限制为最多三名员工。对于前两个级别,这没有问题,因为只有一个部门经理和三个部门经理(永远不会超过三个部门经理),但是我目前在第三级有30个团队成员(每个部门经理管理10个团队成员) )。我的目标是在级别3拥有三个团队成员,在级别4拥有三个团队成员,在级别5拥有三个团队成员,依此类推。团队成员的顺序无关紧要,因此哪个团队成员处于级别3,哪些团队成员处于级别4,等等。

我宁愿避免仅仅为了实现此目标而将团队成员的经理设置为另一团队成员的employee_number。我可以在employee_table中创建另一个称为“ org_list_parent”的列,并指示一个团队成员的“ org_list_parent”是另一团队成员的employee_number,但我希望尽可能避免这样做。

有人对这个问题有什么想法吗?

谢谢。

更新:

使用mathguy的查询,我能够获得与尝试实现的结果最接近的输出。但是,如果可能的话,我想对输出进行一些调整。我正在使用此列表在Oracle Apex中构建组织结构图,并使用mathguy的表和查询获得以下输出:

enter image description here

这与我尝试制作的视觉效果非常接近。 “每级3个团队成员”背后的原因是试图防止图表在水平方向上过大。但是,如果您向左看,例如,雇员1104、1105和1106在1103下,雇员1107在1106下。最好是雇员1104在1101下,雇员1105在1102下,雇员1106在1103下,和1104下面的员工1107。是否有任何方法可以编辑查询以使其直观地产生结果?

更新2:

alexgibbs请求对他提出的两个不同问题的反馈,这些问题是我提出的解决方案。以下是他的第一个查询:

SELECT CASE WHEN LEVEL < 3
          THEN LEVEL
        ELSE 3 + FLOOR((DENSE_RANK() OVER (PARTITION BY MANAGER ORDER BY 
EMPLOYEE_NUMBER ASC ) - 1) / 3) END AS ADJUSTED_LEVEL,
EMPLOYEE_NUMBER, MANAGER
FROM EMPLOYEE_TABLE
START WITH MANAGER IS NULL
CONNECT BY PRIOR EMPLOYEE_NUMBER = MANAGER
ORDER BY 2 ASC, 1 ASC;

以下是此查询的输出,作为Oracle Apex中的列表:

enter image description here

以下是他的第二个查询:

SELECT
CASE WHEN LEVEL < 3
 THEN LEVEL
 ELSE 3 + FLOOR((DENSE_RANK() OVER (PARTITION BY MANAGER ORDER BY 
EMPLOYEE_NUMBER ASC ) - 1) / 3) END AS ADJUSTED_LEVEL,
EMPLOYEE_NUMBER,
MANAGER,
DEPARTMENT
FROM EMPLOYEE_TABLE
START WITH MANAGER IS NULL
CONNECT BY PRIOR EMPLOYEE_NUMBER = MANAGER
ORDER BY
NVL2(MANAGER,1,0) ASC,
DEPARTMENT ASC,
CASE WHEN LEVEL < 3
 THEN LEVEL
 ELSE (MOD((DENSE_RANK() OVER (PARTITION BY MANAGER ORDER BY EMPLOYEE_NUMBER 
ASC )) - 1,3) + 3) END ASC,
ADJUSTED_LEVEL ASC;

以下是Oracle Apex中此查询的输出:

enter image description here

2 个答案:

答案 0 :(得分:2)

这就是我要怎么做。

首先是测试数据(我包括了足够的员工来说明这一点,但每个中层经理的员工人数却不足10)。我忽略了与手头问题无关的电话号码。

{-# language DeriveTraversable #-}

module MyModule where

data MyTree a = MyTree a [MyTree a]
  deriving (Functor, Foldable, Traversable)

然后查询。我希望输出遵循“层次结构顺序”(就像我们不必弄乱级别那样)。为此,我首先运行分层查询,捕获create table employee_table(employee_number, name, manager, department) as select 1001, 'Big Boss', null, 100 from dual union all select 1100, 'Beth Mgr', 1001, 100 from dual union all select 1101, 'Jim' , 1100, 100 from dual union all select 1102, 'Jackie' , 1100, 100 from dual union all select 1103, 'Helen' , 1100, 100 from dual union all select 1104, 'Tom' , 1100, 100 from dual union all select 1105, 'Vance' , 1100, 100 from dual union all select 1106, 'Rosa' , 1100, 100 from dual union all select 1107, 'Chuck' , 1100, 100 from dual union all select 1200, 'Duck Mgr', 1001, 200 from dual union all select 1201, 'Danny' , 1200, 200 from dual union all select 1202, 'Henry' , 1200, 200 from dual union all select 1203, 'Mac' , 1200, 200 from dual union all select 1204, 'Hassan' , 1200, 200 from dual union all select 1205, 'Ann' , 1200, 200 from dual union all select 1300, 'Adam Mgr', 1001, 300 from dual union all select 1301, 'Wendy' , 1300, 300 from dual ; 以对最终结果进行排序,然后在外部查询中修改级别。请注意,我使用ROWNUM作为列名; LVL是保留字,因此不应用作列名。

LEVEL

输出

select   case lvl when 3 then lvl + ceil(rn/3) - 1 else lvl end as lvl,
         employee_number, name, manager, department
from     (
          select     level as lvl, employee_number, name, manager, department,
                     rownum as ord, 
                     row_number() over 
                        (partition by manager order by employee_number) as rn
          from       employee_table
          start with manager is null
          connect by prior employee_number = manager
         )
order by ord
;

答案 1 :(得分:0)

注意:此问题已针对问题的更新进行了重大编辑,并且不确定/未通过顶点进行兼容性测试

下面的解决方案只会将第2级的部门经理添加到第3级以上。但是对于第3级以上的级别,如果如何分配部门经理之外的其他级别无关紧要,则可以根据{{1} }。更新后,三人一组的每个成员都应将伪伪级别直接嵌套在下面,下面是一个示例,该示例根据雇员ID在三个组中分配伪伪级别和子级别为三组。部门。

下面是示例数据集和查询。

employee_id

已编辑 查询:

CREATE TABLE EMPLOYEE_TABLE (
  EMPLOYEE_NUMBER NUMBER,
  MANAGER NUMBER DEFAULT NULL,
  NAME CHARACTER VARYING(64 BYTE),
  DEPARTMENT CHARACTER VARYING(64 BYTE),
  PHONE CHARACTER VARYING(64 BYTE)
);


--Dept Manager
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (10,NULL, 1);
--Section Managers
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (200,10, 2);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (300,10, 3);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (400,10, 4);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (500,10, 5);
-- Section Employees
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (2010,200, 2);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (2020,200, 2);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (2030,200, 2);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (2040,200, 2);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (2050,200, 2);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (2060,200, 2);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (2070,200, 2);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (2080,200, 2);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (2090,200, 2);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (2100,200, 2);

INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (3010,300, 3);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (3020,300, 3);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (3030,300, 3);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (3040,300, 3);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (3050,300, 3);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (3060,300, 3);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (3070,300, 3);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (3080,300, 3);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (3090,300, 3);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (3100,300, 3);

INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (4010,400, 4);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (4020,400, 4);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (4030,400, 4);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (4040,400, 4);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (4050,400, 4);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (4060,400, 4);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (4070,400, 4);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (4080,400, 4);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (4090,400, 4);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (4100,400, 4);


INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (5010,500, 5);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (5020,500, 5);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (5030,500, 5);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (5040,500, 5);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (5050,500, 5);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (5060,500, 5);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (5070,500, 5);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (5080,500, 5);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (5090,500, 5);
INSERT INTO EMPLOYEE_TABLE(EMPLOYEE_NUMBER, MANAGER, DEPARTMENT) VALUES (5100,500, 5);
COMMIT;

结果:

SELECT
CASE WHEN LEVEL < 3
     THEN LEVEL
     ELSE 3 + FLOOR((DENSE_RANK() OVER (PARTITION BY MANAGER ORDER BY EMPLOYEE_NUMBER ASC ) - 1) / 3) END AS ADJUSTED_LEVEL,
EMPLOYEE_NUMBER,
MANAGER,
DEPARTMENT
FROM EMPLOYEE_TABLE
START WITH MANAGER IS NULL
CONNECT BY PRIOR EMPLOYEE_NUMBER = MANAGER
ORDER BY
NVL2(MANAGER,1,0) ASC,
DEPARTMENT ASC,
CASE WHEN LEVEL < 3
     THEN LEVEL
     ELSE (MOD((DENSE_RANK() OVER (PARTITION BY MANAGER ORDER BY EMPLOYEE_NUMBER ASC )) - 1,3) + 3) END ASC,
ADJUSTED_LEVEL ASC;