在左连接中使用 Oracle rank()

Posted

技术标签:

【中文标题】在左连接中使用 Oracle rank()【英文标题】:Using Oracle rank() in a left join 【发布时间】:2014-12-15 19:20:54 【问题描述】:

当我自己运行这个子查询时:

select * 
from (select rpt_nbr, iteration, seq_nbr, emp_id_key, rank() over
     (partition by   emp_id_key order by iteration, seq_nbr) rk 
      from SJTCAPP.LAB_RPT_SPEC_EMP where rpt_nbr = 1572413) 
where rk = rownum

我得到了一个很好的结果,每次迭代只返回 1 个 emp_id_keyseq_nbr,即使可以分配多个 emp_id_key 。但是,当我将其添加到其余查询中时,这很好:

select * from 

SJTCAPP.LAB_RPT r 
left join SJTCAPP.LAB_RPT_SPEC s on s.rpt_nbr = r.rpt_nbr
left join (select * from
    (select rpt_nbr, iteration, seq_nbr, emp_id_key, rank() over (partition by emp_id_key order  
         by iteration, seq_nbr) rk from SJTCAPP.LAB_RPT_SPEC_EMP ) where rk = rownum)
         se on se.rpt_nbr = s.rpt_nbr and se.seq_nbr = s.seq_nbr and se.iteration = s.iteration
left join sjtcapp.employee tech on tech.emp_id_key = se.emp_id_key

我得到 tech.emp_id_key 连接的 NULL 值

更新:

select * from (select rpt_nbr, iteration, seq_nbr, emp_id_key, rank() over (partition by emp_id_key order by iteration, seq_nbr ) rk from SJTCAPP.LAB_RPT_SPEC_EMP where rpt_nbr = 1572413)  where rk = rownum and rpt_nbr = 1572413

上面的查询也给出了“好”的结果。

RPT_NBR ITERATION   SEQ_NBR EMP_ID_KEY  RK
1572413 1   1   44746   1
1572413 1   2   44746   2

在我在这里进行更直接的加入并收到包含各个技术人员姓名的正确查询之前。唯一的问题是,如果分配了多个,则会导致重复,这就是我添加排名子查询的原因。

【问题讨论】:

如果您将where rpt_nbr = 1572413 添加到内部选择中,您会再次获得 1 个 emp_ID_key 吗?可能是当您删除限制条件时,您的一对多会再次可见。或者,如果您从顶部查询示例中删除 where rpt_nbr = 1572413,它是否按照您希望的方式工作?我的怀疑是 SJTCAPP.LAB_RPT 或 SJTCAPP.LAB_RPT_SPEC 会导致在您加入内部选择之前出现空值,这会导致 tech.emp_ID_Key 和 se.emp_id_key 之间出现空值。需要查看示例数据才能知道(SQLFiddle.Com 会在这里提供帮助。) rk = rownum 让我觉得非常可疑。它目前可能会按您的预期工作,但我认为您不能指望这一点。无法保证 rownum 在无序结果上的行为一致。 我也在想同样的事情。将查询更改为以不同的方式使用 rank() 并使用 rn = 1 'code'left join (select * from (select rpt_nbr, iteration, seq_nbr, emp_id_key, rank() over (partition by iteration, seq_nbr order by emp_id_key) rn 来自 SJTCAPP.LAB_RPT_SPEC_EMP ) 其中 rn = 1) se on se.rpt_nbr = s.rpt_nbr and se.seq_nbr = s.seq_nbr and se.iteration = s.iteration 'code' Rank() 在此查询中返回非常大的值,所以我想我不能使用该方法来获取一行。我尝试使用 group by 方法,该方法有效,但查询需要很长时间。我的问题是每个报告可以有多个 SJTCAPP.LAB_RPT_SPEC_EMP,但我不想多次计算它 【参考方案1】:

如果约束迭代和 seq_nbr 是唯一的,您可以使用 exists 代替 rank

SELECT
  rpt_nbr,
  iteration,
  seq_nbr,
  emp_id_key
FROM
  SJTCAPP.LAB_RPT_SPEC_EMP emp
WHERE
  NOT EXISTS
    (
      SELECT
        *
      FROM
        SJTCAPP.LAB_RPT_SPEC_EMP emp2
      WHERE
        emp2.emp_id_key = emp.emp_id_key AND
        emp2.iteration < emp.iteration AND
        emp2.seq_nbr < emp.seq_nbr
    )

【讨论】:

我认为这是正确的方向。当我自己尝试该查询时,我仍然返回了额外的员工。我的目标是每个迭代/序列对只有一名员工。 RPT_NBR 迭代 SEQ_NBR EMP_ID_KEY 1572413 1 2 282167 1572413 1 1 282167 1572413 1 2 44746 1572413 1 1 44746 1572413 1 2 227225 1572413 1 1 1 2722 【参考方案2】:

我最终回到使用 GROUP BY

left join (
    select min(rpt_nbr) as rpt_nbr, min(iteration) as iteration, min(seq_nbr) as seq_nbr, min(emp_id_key) as emp_id_key from LAB_RPT_SPEC_EMP group by rpt_nbr, iteration, seq_nbr
    ) se
    on se.rpt_nbr = s.rpt_nbr and se.seq_nbr = s.seq_nbr and se.iteration = s.iteration

【讨论】:

以上是关于在左连接中使用 Oracle rank()的主要内容,如果未能解决你的问题,请参考以下文章

实体框架在左连接时强制内连接使用 DefaultIfEmpty() 语法

如何将在左连接中具有连接的 sql 转换为查询构建器?

如何在左连接中选择单个记录

Oracle左连接右连接全外连接以及(+)号用法

Oracle之左连接右连接全外连接以及(+)号用法

SQL Server:在左连接查询的执行计划中插入隐藏的“排序”