简体   繁体   English

Oracle SQL如何用更少的代码编写此Join?

[英]Oracle SQL How can I write this Join with less code?

Hello Oracle experts I have a question on how to join two tables correctly. 您好,Oracle专家,我对如何正确连接两个表有疑问。

My first table describes an leave category, the minimum years of service time required for new max vacation leave rollover amount and the max rollover numbers. 我的第一个表格描述了休假类别,新的最大假期休假累计额所需的最短服务时间以及最大累计数。

PTRLVAC_LCAT_CODE   PTRLVAC_YEAR    PTRLVAC_ROLL_MAX_HRS
C1                  0               80                  
C1                  2               88
C1                  5               128
P3                  0               120
P3                  2               128
P3                  5               168

The next table details the employee id, hire date, and leave category 下表详细列出了员工编号,雇用日期和休假类别

PEBEMPL_PIDM    PEBEMPL_HIRE_DATE   PEBEMPL_LCAT_CODE  
1234            01/09/2017          P3
3214            02/01/2014          C1

The join that I have right now relies on a CTE and I'm not sure if it's the easiest solution. 我现在拥有的联接依赖CTE,我不确定这是否是最简单的解决方案。 **I've included the tables here as CTEs **我已将此处的表格列为CTE

with ptrlvac as(
    select 'C1' ptrlvac_lcat_code
          ,0 ptrlvac_year
          ,80 ptrlvac_roll_max_hrs
    from dual union all
    select 'C1', 2, 88 from dual union all
    select 'C1', 5, 128 from dual union all
    select 'P3', 0, 120 from dual union all
    select 'P3', 5, 128 from dual union all
    select 'P3', 2, 168 from dual
    ) , pebempl as(
    select 1234 pebempl_pidm
          ,to_date('09-JAN-2017', 'DD-MON-YYYY') pebempl_hire_date
          ,'P3' pebempl_lcat_code
    from dual
    UNION ALL
    select 3214, to_date('01-FEB-2014','DD-MON-YYYY'), 'C1' from dual
) ,leave as(
    select a.ptrlvac_lcat_code
          ,a.ptrlvac_year
          ,a.ptrlvac_roll_max_hrs
          ,row_number()
              over(partition by a.ptrlvac_lcat_code
                   order by a.ptrlvac_year) rn
    from ptrlvac a
    )
,leave_rules as(
    select a.ptrlvac_lcat_code
          ,a.ptrlvac_year year_start
          ,nvl(b.ptrlvac_year, 100)-1 year_end
          ,a.ptrlvac_roll_max_hrs
    from leave a
         left join leave b
         on  a.ptrlvac_lcat_code = b.ptrlvac_lcat_code
         and a.rn = b.rn - 1
    )
select distinct pebempl_pidm
          ,pebempl_hire_date
          ,floor(months_between(to_date(:seldate, 'DD-MON-YYYY'), pebempl_hire_date) / 12)  as service_years
          ,pebempl_lcat_code as lcat
          ,b.ptrlvac_roll_max_hrs
    from pebempl a
         inner join leave_rules b
         on a.pebempl_lcat_code = b.ptrlvac_lcat_code
         and floor(months_between(to_date(:seldate, 'DD-MON-YYYY'), pebempl_hire_date) / 12) between b.year_start and b.year_end

Any help to save some keystrokes would be greatly appreciated. 任何节省一些按键的帮助将不胜感激。

Thanks in advance. 提前致谢。

I'm not sure if this does what you want: 我不确定这是否满足您的要求:

select
t2.PEBEMPL_PIDM,
t1.PTRLVAC_ROLL_MAX_HRS
from test1 t1, test2 t2
where
t1.PTRLVAC_LCAT_CODE = t2.PEBEMPL_LCAT_CODE and
t1.PTRLVAC_YEAR = 
(select max(t1s.PTRLVAC_YEAR) from test1 t1s
where t1s.PTRLVAC_LCAT_CODE = t2.PEBEMPL_LCAT_CODE
and (sysdate-PEBEMPL_HIRE_DATE)/365 >= t1s.PTRLVAC_YEAR);

Here are the results I got based on your test data: 以下是我根据您的测试数据得出的结果:

PEBEMPL_PIDM PTRLVAC_ROLL_MAX_HRS                                               
------------ --------------------                                               
        3214                   88                                               
        1234                  120                                               

Bobby 鲍比

Had this thought over lunch, further reducing @BobbyDurret's answer: 在午餐时有这种想法,进一步减少了@BobbyDurret的答案:

select
t2.PEBEMPL_PIDM,
max(t1.PTRLVAC_ROLL_MAX_HRS)
from ptrlvac t1, pebempl t2
where
t1.PTRLVAC_LCAT_CODE = t2.PEBEMPL_LCAT_CODE and
(sysdate-PEBEMPL_HIRE_DATE)/365 >= t1.PTRLVAC_YEAR
group by t2.PEBEMPL_PIDM

Assumes the Max_Hrs always increases for more years of service. 假设Max_Hrs在使用年限更长的时候总是会增加。

Instead of using row_number and filtering in a separate CTE, use lead: 代替使用row_number和在单独的CTE中进行过滤,请使用Lead:

with leave_rules as
(
    select a.ptrlvac_lcat_code
          ,a.ptrlvac_year as year_start
          ,a.ptrlvac_roll_max_hrs
          ,lead(ptrlvac_year,1,10000) over (partition by ptrlvac_lcat_code
                                 order by ptrlvac_year)
          as year_end
    from ptrlvac a
)
select distinct pebempl_pidm
          ,pebempl_hire_date
          ,floor(months_between(sysdate, pebempl_hire_date) / 12)  as service_years
          ,pebempl_lcat_code as lcat
          ,b.ptrlvac_roll_max_hrs
    from pebempl a
         inner join leave_rules b
         on a.pebempl_lcat_code = b.ptrlvac_lcat_code
         and floor(months_between(sysdate, pebempl_hire_date) / 12) between year_start and year_end

Combines your 2 CTE's to compute "leave_rules" into 1. I just put sysdate for the date variable so I could test easily - you probably want to use the bind variables as you originally had. 将您的2个CTE组合起来以将“ leave_rules”计算为1。我只将sysdate用作date变量,以便可以轻松进行测试-您可能希望像原来一样使用绑定变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM