sqloracle-database

Taking the record with the max date with join


I have Oracle table t1 with date column and several other columns, and table t2 with date only.

I want to get all t2.date with t1 record which have max t1.date <= t2.date

if t1 enter image description here and t2 enter image description here then result must be enter image description here

Data Example

with d as (select trunc(sysdate) ate from dual),
    t1 as (select d.ate - 2 dat, 11 val1, 22 val2 from dual, d union all
           select d.ate, 33, 44 from dual, d union all
           select d.ate + 2, 55, 66 from dual, d),
    t2 as (select d.ate - 3 dat from dual, d union all
           select d.ate - 1 from dual, d union all
           select d.ate from dual, d union all
           select d.ate + 3 from dual, d)
 select t2.dat--, 
        --(t1.val1 where t1.dat <= t2.dat and t1.dat = max) val1,
        --(t1.val2 where t1.dat <= t2.dat and t1.dat = max) val2
   from t2

Solution

  • From Oracle 12, you can use OUTER APPLY to preform a correlated join and FETCH FIRST ROW ONLY to get the maximum:

    SELECT *
    FROM   t2
           OUTER APPLY (
             SELECT val1, val2
             FROM   t1
             WHERE  t1.dat <= t2.dat
             ORDER BY t1.dat DESC
             FETCH FIRST ROW ONLY
           )
    

    Or LEFT [OUTER] JOIN LATERAL:

    SELECT *
    FROM   t2
           LEFT JOIN LATERAL (
             SELECT val1, val2
             FROM   t1
             WHERE  t1.dat <= t2.dat
             ORDER BY t1.dat DESC
             FETCH FIRST ROW ONLY
           )
           ON (1 = 1)
    

    Or, in earlier versions, you can join the tables using an OUTER JOIN and aggregate using KEEP to get the value for the latest date:

    SELECT MAX(t2.dat) AS dat,
           MAX(t1.val1) KEEP (DENSE_RANK LAST ORDER BY t1.dat) AS val1,
           MAX(t1.val2) KEEP (DENSE_RANK LAST ORDER BY t1.dat) AS val2
    FROM   t2
           LEFT OUTER JOIN t1
           ON t1.dat <= t2.dat
    GROUP BY t2.ROWID
    

    Which, for the sample data:

    CREATE TABLE t1 (dat, val1, val2) AS
    SELECT TRUNC(SYSDATE)-2, 11, 22 FROM DUAL UNION ALL
    SELECT TRUNC(SYSDATE)+0, 33, 44 FROM DUAL UNION ALL
    SELECT TRUNC(SYSDATE)+2, 55, 66 FROM DUAL;
    
    CREATE TABLE t2 (dat) AS
    SELECT TRUNC(SYSDATE)-3 FROM DUAL UNION ALL
    SELECT TRUNC(SYSDATE)-1 FROM DUAL UNION ALL
    SELECT TRUNC(SYSDATE)+0 FROM DUAL UNION ALL
    SELECT TRUNC(SYSDATE)+3 FROM DUAL;
    

    All output:

    DAT VAL1 VAL2
    2025-11-29 00:00:00 null null
    2025-12-01 00:00:00 11 22
    2025-12-02 00:00:00 33 44
    2025-12-05 00:00:00 55 66

    fiddle