How do I select the next closest received date from table2 relative to the requested date in table 1? Included the desired result at the end. I am using Oracle SQL.
Table1:
PO RequestedDate
14888 01/12/2018
14733 02/12/2018
14555 05/12/2018
Table2:
PO ReceivedDate
14888 01/11/2018
14888 01/14/2018
14733 2/11/2018
14733 2/12/2018
14555 07/23/2018
14555 09/23/2018
Expected Result:
PO RequestedDate NearestReceivedDate
14888 01/12/2018 01/14/2018
14733 02/12/2018 02/12/2018
14555 05/12/2018 07/23/2018
CodePudding user response:
WITH TABLE_1(PO,REQUESTED_DATE)AS
(
SELECT 14888, TO_DATE('01/12/2018','MM/DD/YYYY') FROM DUAL UNION ALL
SELECT 14733, TO_DATE('02/12/2018','MM/DD/YYYY') FROM DUAL UNION ALL
SELECT 14555, TO_DATE('05/12/2018','MM/DD/YYYY') FROM DUAL
),
TABLE_2(PO,Received_Date) AS
(
SELECT 14888, TO_DATE('01/11/2018','MM/DD/YYYY') FROM DUAL UNION ALL
SELECT 14888, TO_DATE('01/14/2018','MM/DD/YYYY') FROM DUAL UNION ALL
SELECT 14733, TO_DATE('02/11/2018','MM/DD/YYYY') FROM DUAL UNION ALL
SELECT 14733, TO_DATE('02/12/2018','MM/DD/YYYY') FROM DUAL UNION ALL
SELECT 14555, TO_DATE('07/23/2018','MM/DD/YYYY') FROM DUAL UNION ALL
SELECT 14555, TO_DATE('09/23/2018','MM/DD/YYYY') FROM DUAL
)
SELECT T.PO,CAST(T.REQUESTED_DATE AS DATE),X.RR
FROM TABLE_1 T
CROSS APPLY
(
SELECT MIN(T2.Received_Date)RR
FROM TABLE_2 T2
WHERE T.PO=T2.PO
AND CAST(T2.Received_Date AS DATE)>=CAST(T.REQUESTED_DATE AS DATE)
)X
https://dbfiddle.uk/?rdbms=oracle_21&fiddle=81cc657918a214d0f118f870eeb67a3d
CodePudding user response:
From Oracle 12, you can use a LATERAL join and FETCH FIRST ROW ONLY:
SELECT *
FROM table1 t1
CROSS JOIN LATERAL (
SELECT t2.receiveddate
FROM table2 t2
WHERE t1.po = t2.po
AND t1.requesteddate <= t2.receiveddate
ORDER BY
t2.receiveddate
FETCH FIRST ROW ONLY
)
Which, for the sample data:
CREATE TABLE Table1 (PO, RequestedDate) AS
SELECT 14888, DATE '2018-01-12' FROM DUAL UNION ALL
SELECT 14733, DATE '2018-02-12' FROM DUAL UNION ALL
SELECT 14555, DATE '2018-05-12' FROM DUAL;
CREATE TABLE Table2 (PO, ReceivedDate) AS
SELECT 14888, DATE '2018-01-11' FROM DUAL UNION ALL
SELECT 14888, DATE '2018-01-14' FROM DUAL UNION ALL
SELECT 14733, DATE '2018-02-11' FROM DUAL UNION ALL
SELECT 14733, DATE '2018-02-12' FROM DUAL UNION ALL
SELECT 14555, DATE '2018-07-23' FROM DUAL UNION ALL
SELECT 14555, DATE '2018-09-23' FROM DUAL;
Outputs:
PO REQUESTEDDATE RECEIVEDDATE 14888 12-JAN-18 14-JAN-18 14733 12-FEB-18 12-FEB-18 14555 12-MAY-18 23-JUL-18
db<>fiddle here
CodePudding user response:
You can also use below solution for your purpose
select t1.*, t2.ReceivedDate
from Table1 t1, Table2 t2
WHERE t1.PO = t2.PO
AND t1.RequestedDate <= t2.ReceivedDate
AND t2.ReceivedDate = (
SELECT MIN(t3.ReceivedDate)
FROM Table2 t3
WHERE t3.PO = t1.PO
AND t1.RequestedDate <= t3.ReceivedDate
)
;
db<>fiddle here
CodePudding user response:
As a tricky option you may transform an input dataset to a "vertical" event-like structure, order all the dates and use match_recognize to select the row rigth after the receiveddate. It doesn't require nested loops compared to the lateral join/cross apply, which significantly affects the performance in case of large dataset in Table1, and doesn't multiply the data compared to plain join of two tables and min aggregation.
Based on the @MT0's data:
with t as ( select po, /*Prepend numeric constant for stable sort order*/ '0_REQ' as src, RequestedDate as dt from table1 union all select po, '1_RCV' as src, ReceivedDate as dt from table2 ) select /* gather_plan_statistics*/ * from t match_recognize( partition by po /*Order by dates, then by event type*/ order by dt asc, src asc measures /*Requested date is taken from a request event*/ req.dt as RequestedDate, /*Received date is taken from a receive event*/ rcv.dt as ReceivedDate pattern (req rcv) define req as src = '0_REQ', rcv as src = '1_RCV' )PO | REQUESTEDDATE | RECEIVEDDATE ----: | :------------ | :----------- 14555 | 12-MAY-18 | 23-JUL-18 14733 | 12-FEB-18 | 12-FEB-18 14888 | 12-JAN-18 | 14-JAN-18
db<>fiddle here
And just to compare at randomly upscaled dataset: db<>fiddle
