Oracle-加入活动时的最新状态

时间:2019-04-02 18:40:04

标签: sql oracle

我有两个表-一个表涉及员工活动,另一个表涉及employee_status。问题是员工状态随时间而变化,因此我需要像会议时一样加入状态。

>>> employee_activity

    id     session_start
    emp1    1/1/2019
    emp1    2/22/2019
    emp1    3/1/2019
    emp2    1/4/2019
    emp2    2/23/2019

>>> employee_status     

id   status effective date
emp1    a   1/1/2018
emp1    b   2/1/2019
emp1    c   3/5/2019
emp2    a   6/1/2018
emp2    b   1/1/2019

所以我开始写一些东西,以确保它在活动结束后会忽略状态,但是我在弄清楚如何只选择最新状态方面有些挣扎。查询只需要将状态与最大     小于会话开始日期

    SELECT * FROM employee_activity a
    LEFT join employee_status s on a.id = s.id WHERE s.effective_date <= a.session_start
-- how do I join only the most recent status?

上面两个表的期望输出将是

>>> my_output       
id  session_start   status
emp1    1/1/2019    a
emp1    2/22/2019   b
emp1    3/1/2019    b
emp2    1/4/2019    b
emp2    2/23/2019   b

谢谢!

2 个答案:

答案 0 :(得分:2)

首先从状态计算有效间隔,即,您没有开始EFFECTIVE_DATE的开始和结束时间戳。

请注意,我使用默认的开放结束日期,并从结束日期中减去一秒钟以获取封闭间隔,可以使用BETWEEN来查询封闭间隔。

比键上的简单连接和添加时间之间的约束:

with emp as (
select ID, STATUS, EFFECTIVE_DATE status_valid_from,
lead(EFFECTIVE_DATE - INTERVAL '1' SECOND,1,DATE'2500-01-01') 
    over (partition by id order by EFFECTIVE_DATE) as status_valid_to
from employee_status)
SELECT a.id, a.SESSION_START, s.STATUS, s.STATUS_VALID_FROM 
FROM employee_activity a
LEFT join emp s 
on a.id = s.id and  session_start between s.status_valid_from and s.status_valid_to
order by 1,2;

ID   SESSION_START       S STATUS_VALID_FROM  
---- ------------------- - -------------------
emp1 01.01.2019 00:00:00 a 01.01.2018 00:00:00
emp1 22.02.2019 00:00:00 b 01.02.2019 00:00:00
emp1 01.03.2019 00:00:00 b 01.02.2019 00:00:00
emp2 04.01.2019 00:00:00 b 01.01.2019 00:00:00
emp2 23.02.2019 00:00:00 b 01.01.2019 00:00:00

样本数据

create table employee_activity as 
select    'emp1' id,     to_date('1/1/2019','mm/dd/yyyy') session_start from dual union all 
select    'emp1' id,     to_date('2/22/2019','mm/dd/yyyy') session_start from dual union all 
select    'emp1' id,     to_date('3/1/2019','mm/dd/yyyy') session_start from dual union all 
select    'emp2' id,     to_date('1/4/2019','mm/dd/yyyy') session_start from dual union all 
select    'emp2' id,     to_date('2/23/2019','mm/dd/yyyy') session_start from dual;

create table  employee_status  as     
select 'emp1' id, 'a'status, to_date('1/1/2018','mm/dd/yyyy') effective_date from dual union all 
select 'emp1' id, 'b'status, to_date('2/1/2019','mm/dd/yyyy') effective_date from dual union all 
select 'emp1' id, 'c'status, to_date('3/5/2019','mm/dd/yyyy') effective_date from dual union all 
select 'emp2' id, 'a'status, to_date('6/1/2018','mm/dd/yyyy') effective_date from dual union all 
select 'emp2' id, 'b'status, to_date('1/1/2019','mm/dd/yyyy') effective_date from dual;

答案 1 :(得分:0)

您可以使用相关子查询来做到这一点:

select ea.*,
       (select max(es.status) keep (dense_rank first order by es.effective_date desc)
        from employee_status es
        where es.id = ea.id and es.effective_date <= ea.session_start
       ) as status
from employee_activity ea;

在Oracle 12C +中,更加直观:

select ea.*,
       (select es.status
        from employee_status es
        where es.id = ea.id and es.effective_date <= ea.session_start
        order by es.effective_date desc
        fetch first 1 row only
       ) as status
from employee_activity ea;