简体   繁体   English

在 Oracle SQL 中依次选择下一个最接近的日期

[英]Choose the next closest date after another in Oracle SQL

How do I select the next closest received date from table2 relative to the requested date in table 1?相对于表 1 中的请求日期,如何从表 2 中选择下一个最接近的接收日期? Included the desired result at the end.最后包括所需的结果。 I am using Oracle SQL.我正在使用 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
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 https://dbfiddle.uk/?rdbms=oracle_21&fiddle=81cc657918a214d0f118f870eeb67a3d

From Oracle 12, you can use a LATERAL join and FETCH FIRST ROW ONLY :从 Oracle 12 开始,您可以使用LATERAL join 和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 14888 12-JAN-18 18 年 1 月 12 日 14-JAN-18 18 年 1 月 14 日
14733 14733 12-FEB-18 18 年 2 月 12 日 12-FEB-18 18 年 2 月 12 日
14555 14555 12-MAY-18 18 年 5 月 12 日 23-JUL-18 18 年 7 月 23 日

db<>fiddle here db<> 在这里摆弄

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 db<> 在这里摆弄

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 .作为一个棘手的选项,您可以将输入数据集转换为“垂直”类似事件的结构,对所有日期进行排序并使用match_recognizereceiveddate之后选择行。 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.与横向连接/交叉应用相比,它不需要嵌套循环,这会显着影响Table1中大型数据集的性能,并且与两个表的普通joinmin聚合相比,不会将数据相乘。

Based on the @MT0 's data:基于@MT0的数据:

 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 | 14555 | 12-MAY-18 | 18 年 5 月 12 日 | 23-JUL-18 18 年 7 月 23 日   
14733 | 14733 | 12-FEB-18 | 18 年 2 月 12 日 | 12-FEB-18 18 年 2 月 12 日   
14888 | 14888 | 12-JAN-18 | 18 年 1 月 12 日 | 14-JAN-18 18 年 1 月 14 日   

db<>fiddle here db<> 在这里摆弄

And just to compare at randomly upscaled dataset: db<>fiddle只是为了比较随机放大的数据集: db<>fiddle

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

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