Home > other >  To fetch the rehire period using lag n lead function
To fetch the rehire period using lag n lead function

Time:01-03

Wanted to check whether the employee got rehired to a contract or not. If he is rehired then return the rehire period . If the multiple employees got rehired then return all their rehire period .

Sample data:(Table 'Contract')
Employee_id        Period         Contract 
111                  202204         1NA
111                  202205          1NA
111                  202206           1NA
112                  202207           1NA
112                  202208           1NA
111                  202209           1NA

In the above case the output should be ,

Employee_id       Period           Contract
111               202209            1NA

The query should first check whether the employee got rehired or not, if so then return the rehire period. If that contract has got no rehire's then return NULL.

Any other logic other than lag n lead will also be Appreciated!

Thanks in advance:)

Image of the sample data

CodePudding user response:

Use LAG to identify if the previous period interval, then only select the ones where the interval > 1

create table  contracts (employee_id,period,contract) as 
(
  SELECT 111, 202204,'1NA' FROM DUAL UNION ALL
  SELECT 111, 202205,'1NA' FROM DUAL UNION ALL
  SELECT 111, 202206,'1NA' FROM DUAL UNION ALL
  SELECT 111, 202209,'1NA' FROM DUAL UNION ALL
  SELECT 112, 202207,'1NA' FROM DUAL UNION ALL
  SELECT 112, 202208,'1NA' FROM DUAL 
);

Table CONTRACTS created.

with contracts_w_lags (
   employee_id
   ,period
   ,last_period
   ,contract
) as ( select employee_id
             ,period
             ,lag(period)
               over(partition by employee_id
                    order by period)
             ,contract
  from contracts
)
select employee_id
      ,period 
      ,contract
  from contracts_w_lags
 where period - nvl( last_period ,period ) > 1;


EMPLOYEE_ID     PERIOD CON
----------- ---------- ---
        111     202209 1NA

Note that your sample data only has periods within the same year. This example will fail if periods cross years.

To overcome that, create a pseudo "periods" table with a rownumber to identify consecutive rows:

create table  contracts (employee_id,period,contract) as 
(
  SELECT 111, 202111,'1NA' FROM DUAL UNION ALL
  SELECT 111, 202112,'1NA' FROM DUAL UNION ALL
  SELECT 111, 202201,'1NA' FROM DUAL UNION ALL
  SELECT 111, 202203,'1NA' FROM DUAL UNION ALL
  SELECT 112, 202207,'1NA' FROM DUAL UNION ALL
  SELECT 112, 202208,'1NA' FROM DUAL 
);


Table CONTRACTS created.


with month_count ( cnt ) as 
( select months_between(
   to_date( max(period) ,'YYYYMM' )
  ,to_date( min(period) ,'YYYYMM' ))
  from contracts
),contract_start ( dt ) as 
( select to_date( min(period) ,'YYYYMM' )
  from contracts
),contract_periods ( period ,rn ) as 
( select to_char( add_months( c.dt ,level - 1 ) ,'YYYYMM' )
        ,row_number() over( order by add_months( c.dt ,level - 1 ) ) 
    from contract_start c
        ,month_count m 
    connect by level <= m.cnt   1 
),contracts_w_lags ( employee_id ,period ,contract ,period_rn ,last_period_rn ) as 
( select c.employee_id
        ,c.period
        ,c.contract
        ,p.rn
        ,lag(p.rn) over(partition by c.employee_id order by p.rn )
  from contracts c
       join contract_periods p on c.period = p.period
)
select employee_id
      ,period
      ,contract
  from contracts_w_lags
 where period_rn - nvl( last_period_rn ,period_rn ) > 1;



EMPLOYEE_ID     PERIOD CON
----------- ---------- ---
        111     202209 1NA

CodePudding user response:

The answer (after comments) is at the end....

It is unclear what is your expected result with this sample data:

WITH
    contracts (EMP_ID, PERIOD, CONTRACT) as 
        (
            SELECT 111, 202204, '1NA' FROM DUAL UNION ALL
            SELECT 111, 202205, '1NA' FROM DUAL UNION ALL
            SELECT 111, 202206, '1NA' FROM DUAL UNION ALL
            SELECT 112, 202207, '1NA' FROM DUAL UNION ALL
            SELECT 112, 202208, '1NA' FROM DUAL UNION ALL
            SELECT 111, 202209, '1NA' FROM DUAL 
        )

There are some multiple consecutive periods for both sample eployees. One of the options is to show first and last periods for emps with multiple periods:

SELECT  EMP_ID, Min(PREV_PERIOD) "FIRST_PERIOD", Max(PERIOD) "LAST_PERIOD", CONTRACT
FROM    (Select EMP_ID, PERIOD, CONTRACT, 
              LAG(PERIOD, 1, 0) OVER(Partition By EMP_ID Order By PERIOD) "PREV_PERIOD"
       From contracts)
WHERE   PREV_PERIOD != 0
GROUP BY  EMP_ID, CONTRACT
--  
--  R e s u l t :
--      EMP_ID FIRST_PERIOD LAST_PERIOD CONTRACT
--  ---------- ------------ ----------- --------
--         111       202204      202209 1NA      
--         112       202207      202208 1NA  

... another could be to show them all :

SELECT  EMP_ID, PERIOD "PERIOD", PREV_PERIOD "PREV_PERIOD", CONTRACT
FROM    (Select EMP_ID, PERIOD, CONTRACT, 
              LAG(PERIOD, 1, 0) OVER(Partition By EMP_ID Order By PERIOD) "PREV_PERIOD"
       From contracts)
WHERE   PREV_PERIOD != 0
--  
--  R e s u l t :
--      EMP_ID     PERIOD PREV_PERIOD CONTRACT
--  ---------- ---------- ----------- --------
--         111     202205      202204 1NA      
--         111     202206      202205 1NA      
--         111     202209      202206 1NA      
--         112     202208      202207 1NA  

... and if you want the same with LEAD() function

SELECT  EMP_ID, PERIOD "PERIOD", NEXT_PERIOD "NEXT_PERIOD", CONTRACT
FROM    (Select EMP_ID, PERIOD, CONTRACT, 
              LEAD(PERIOD, 1, 0) OVER(Partition By EMP_ID Order By PERIOD) "NEXT_PERIOD"
       From contracts)
WHERE   NEXT_PERIOD != 0
--  
--  R e s u l t :
--      EMP_ID     PERIOD NEXT_PERIOD CONTRACT
--  ---------- ---------- ----------- --------
--         111     202204      202205 1NA      
--         111     202205      202206 1NA      
--         111     202206      202309 1NA      
--         112     202207      202208 1NA     
--         112     202208      202207 1NA      

It is pretty much the same - just showing next period instead of previous.
NOTE: If rehire to a contract means the same contract then -
OVER(Partition By EMP_ID, CONTRACT ....)

To do the opposite (non-consecutive periods):

SELECT  EMP_ID, PERIOD "PERIOD", NEXT_PERIOD "NEXT_PERIOD", CONTRACT
FROM    (Select EMP_ID, PERIOD, CONTRACT, 
              LEAD(PERIOD, 1, 0) OVER(Partition By EMP_ID Order By PERIOD) "NEXT_PERIOD"
       From contracts)
WHERE   NEXT_PERIOD != 0 And CASE WHEN SubStr(NEXT_PERIOD, 1, 4) = SubStr(PERIOD, 1, 4) 
                                THEN NEXT_PERIOD - PERIOD
                           ELSE NEXT_PERIOD - (PERIOD   88)  -- handling the year  change
                           END > 1
--  
--  R e s u l t :
--      EMP_ID     PERIOD NEXT_PERIOD CONTRACT
--  ---------- ---------- ----------- --------
--         111     202206      202209 1NA        
  • Related