【问题标题】:Recursively finding the next non-self, non-null value in a table using PL/SQL使用 PL/SQL 在表中递归查找下一个非自非空值
【发布时间】:2017-06-28 03:40:02
【问题描述】:

我有一个由两个元素组成的数据集:代表工作层次结构的职位编号,以及分配给这些职位编号的人员。每个位置编号也有一个父位置。

并非每个职位都有指定人员。此外,可以将人员分配到多个职位(例如,销售经理也可能被任命为临时区域销售经理)。

我要做的是为给定的人找到下一个非自我、非空经理。

以下是数据集的示例。让我们称表为“位置”:

Position  Title              Employee_ID     Name      Parent_Position

001       Salesperson            A           Mike            002
002       Sales Manager          B           Rob             003
003       Regional Sales Mgr     B           Rob             004
004       VP of Sales          [NULL]       [NULL]           005
005       Executive VP           C           Liz             006
006       CEO                    D           Annie          [NULL]

我试图实现的输出如下(尽管附加列很好):

Employee_ID     Name     Manager_ID    Manager_Name

    A           Mike         B            Rob
    B           Rob          C            Liz
    C           Liz          D            Annie
    D           Annie      [NULL]        [NULL]

上周,我在 CONNECT BY PRIOR 上进行了相当多的尝试,并在此处和通过通用 Googleverse 进行搜索。我能找到的最接近的例子是以下示例:

Oracle SQL recursion to find first instance of non-null column value

但是,这个数据集的不同之处足以让我无法将该答案应用于我的具体问题,因为我实际上是在剥离职位到职位的信息来获取人与人之间的信息。

我的背景更多是面向对象编程而不是 SQL,所以我的直觉是编写一个函数来处理这个问题,但我不是 DBA,所以我只有查询访问权限。我已经阅读了 Oracle 的 CONNECT BY PRIOR 文档,当涉及到只是遍历职位层次结构时,我没有任何问题,但我被困在如何根据要求获取人员信息(非自我非-null)。

注意:这是我在这里的第一篇文章。请让我知道我是否应该提供更多信息或是否应该澄清任何事情。

【问题讨论】:

  • 请提供一些您尝试过的示例。文字描述是不够的。
  • 你将如何在现实生活中使用它?输入似乎是员工 ID;但是数据集不适合那个。例如,如果您输入员工 id = B,那么层次结构从哪里开始?
  • 关于样本——我明天会尝试上传一些。数据集有点复杂,而且都是专有/机密的东西,所以我必须淡化它来展示一个例子,这需要一些时间。在现实生活中使用它:我有一个用户从我们的 ERP 访问第三方软件的文件提要。 ERP 都是基于职位的。 3rd 方软件都是基于用户的。因此,我需要为每个用户发送一个经理,而不是发送职位层次结构。这基本上是一个子查询,如果有意义的话,我将使用它来左外连接到主用户查询。

标签: oracle recursion plsql oracle11g


【解决方案1】:

首先获取每个员工的所有经理的列表。为此使用递归 CTE。然后根据employee_id 对记录进行排名,优先选择职位尽可能接近员工的非空经理。

with cte(emp_pos, emp_id, mgr_pos, mgr_id, levl, parent_position) as
(
  select position as emp_pos, null as mgr_pos, null as mgr_id, 1 as levl, parent_position
  from positions 
  where employee_id is not null
  union all
  select
    cte.emp_pos, 
    p.position as mgr_pos, 
    p.employee_id as mgr_id, 
    cte.levl + 1 as levl, 
    p.parent_position
  from cte
  join positions p on p.position = cte.parent_position
)
select 
  emp_pos.employee_id,
  emp_pos.name, 
  mgr_pos.employee_id as manager_id,
  mgr_pos.name as manager_name
from
(
  select 
    cte.*,
    row_number() over (
      partition by cte.emp_pos
      order by case when cte.mgr_id is null then 2 else 1 end, cte.levl) as rn
  from cte
  where (cte.emp_pos <> cte.mgr_pos or cte.mgr_pos is null)
)  
join positions emp_pos on emp_pos.position = cte.emp_pos
left join positions mgr_pos on mgr_pos.position = cte.mgr_pos
where cte.rn = 1;

我知道这看起来很复杂(甚至查询中可能存在缺陷),但我想不出更简单的查询。

【讨论】:

  • 谢谢。我想我知道你在这里做什么,这可能会奏效。我明天试一试,然后告诉你。
猜你喜欢
  • 2013-07-09
  • 2021-10-01
  • 2020-03-13
  • 2021-10-31
  • 1970-01-01
  • 2021-12-03
  • 2021-06-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多