oracle sql 从前一个日期检索后续日期

oracle sql to retrieve followup dates from a preceding date

CREATE TABLE tst_tbl
(
   id                 NUMBER,
   last_name          VARCHAR2 (50),
   first_name         VARCHAR2 (50),
   dob                DATE,
   register_dt        DATE,
   register_loc       VARCHAR2 (50),
   visit_dt           DATE,
   visit_loc          VARCHAR2 (50),
   visit_comments   VARCHAR2 (30)
);


INSERT INTO tst_tbl VALUES(1234, 'John', 'Smith', to_date('12/01/1980','MM/DD/YYYY') , to_date('09/05/2017' ,'MM/DD/YYYY')   ,'NEW YORK',  to_date('02/26/2018','MM/DD/YYYY'), 'NEW JERSEY', '');
INSERT INTO tst_tbl VALUES(1234, 'John', 'Smith', to_date('12/01/1980','MM/DD/YYYY') , to_date('09/05/2017' ,'MM/DD/YYYY')   ,'NEW YORK',  to_date('2/12/2018', 'MM/DD/YYYY'),'NEW JERSEY', '');
INSERT INTO tst_tbl VALUES(1234, 'John', 'Smith', to_date('12/01/1980','MM/DD/YYYY') , to_date('09/05/2017' ,'MM/DD/YYYY')   ,'NEW YORK',  to_date('11/6/2017', 'MM/DD/YYYY'),'NEW JERSEY', '');
INSERT INTO tst_tbl VALUES(1234, 'John', 'Smith', to_date('12/01/1980','MM/DD/YYYY') , to_date('09/05/2017' ,'MM/DD/YYYY')   ,'NEW YORK',  to_date('10/23/2017','MM/DD/YYYY'), 'NEW JERSEY', '');
INSERT INTO tst_tbl VALUES(1234, 'John', 'Smith', to_date('12/01/1980','MM/DD/YYYY') , to_date('09/05/2017' ,'MM/DD/YYYY')   ,'NEW YORK',  to_date('3/27/2018', 'MM/DD/YYYY'),'NEW JERSEY', '');
INSERT INTO tst_tbl VALUES(1234, 'John', 'Smith', to_date('12/01/1980','MM/DD/YYYY') , to_date('09/05/2017' ,'MM/DD/YYYY')   ,'NEW YORK',  to_date('3/19/2018', 'MM/DD/YYYY'),'NEW JERSEY', '');
INSERT INTO tst_tbl VALUES(1234, 'John', 'Smith', to_date('12/01/1980','MM/DD/YYYY') , to_date('09/05/2017' ,'MM/DD/YYYY')   ,'NEW YORK',  to_date('9/11/2017', 'MM/DD/YYYY'),'NEW JERSEY', '');
INSERT INTO tst_tbl VALUES(1234, 'John', 'Smith', to_date('12/01/1980','MM/DD/YYYY') , to_date('2/7/2018'   ,'MM/DD/YYYY')   ,  'NEW YORK',to_date('11/6/2017 ','MM/DD/YYYY'), 'NEW JERSEY', '');
INSERT INTO tst_tbl VALUES(1234, 'John', 'Smith', to_date('12/01/1980','MM/DD/YYYY') , to_date('2/7/2018'   ,'MM/DD/YYYY')   ,  'NEW YORK',to_date('3/19/2018', 'MM/DD/YYYY'),'NEW JERSEY', '');
INSERT INTO tst_tbl VALUES(1234, 'John', 'Smith', to_date('12/01/1980','MM/DD/YYYY') , to_date('2/7/2018'   ,'MM/DD/YYYY')   ,  'NEW YORK',to_date('9/11/2017', 'MM/DD/YYYY'),'NEW JERSEY', '');
INSERT INTO tst_tbl VALUES(1234, 'John', 'Smith', to_date('12/01/1980','MM/DD/YYYY') , to_date('2/7/2018'   ,'MM/DD/YYYY')   ,  'NEW YORK',to_date('3/27/2018', 'MM/DD/YYYY'),'NEW JERSEY', '');
INSERT INTO tst_tbl VALUES(1234, 'John', 'Smith', to_date('12/01/1980','MM/DD/YYYY') , to_date('2/7/2018'   ,'MM/DD/YYYY')   ,  'NEW YORK',to_date('2/26/2018', 'MM/DD/YYYY'),'NEW JERSEY', '');
INSERT INTO tst_tbl VALUES(1234, 'John', 'Smith', to_date('12/01/1980','MM/DD/YYYY') , to_date('2/7/2018'   ,'MM/DD/YYYY')   ,  'NEW YORK',to_date('10/23/2017','MM/DD/YYYY'), 'NEW JERSEY', '');
INSERT INTO tst_tbl VALUES(1234, 'John', 'Smith', to_date('12/01/1980','MM/DD/YYYY') , to_date('2/7/2018'   ,'MM/DD/YYYY')   ,  'NEW YORK',to_date('2/12/2018', 'MM/DD/YYYY'),'NEW JERSEY', '');
COMMIT;

我想要在注册日期后立即获得访问信息(visit_dt、visit_loc、..)。

例如:

1234, John, Smith, 12/01/1980, 09/05/2017,  NEW YORK, 9/11/2017, NEW JERSEY
1234, John, Smith, 12/01/1980, 2/7/2018,  NEW YORK, 2/12/2018, NEW JERSEY

我尝试使用以下逻辑对注册日期和访问日期进行排序,然后使用 lead 检索以下日期并仅过滤注册日期。但是,我无法添加如上所示的其他字段..

 SELECT 
      dt, vst_type, register_dt, vst_dt
    FROM 
    (
      SELECT 
        id, dt, vst_type, 
        dt AS register_dt,
        ROW_NUMBER () OVER 
            ( 
              PARTITION BY id, dt ORDER BY
                CASE 
                  WHEN vst_type = 'REGISTER_DT' THEN 1 ELSE 2 END
            )
        AS vst_dt_rnum,
        LEAD(dt) OVER (PARTITION BY id ORDER BY dt) AS vst_dt
      FROM 
      (
        SELECT id, register_dt AS dt, 'REGISTER_DT' vst_type FROM tst_tbl
        UNION
        SELECT id, visit_dt AS dt, 'VISIT_DT' vst_type FROM tst_tbl
      )
    )
    WHERE vst_dt_rnum = 1 AND vst_type = 'REGISTER_DT'

我觉得你把事情复杂化了。如果访问日期在注册日期后 <30 天,您可以通过以下方法添加指示符。如果出于某种原因这对您不起作用,请编辑您的问题并添加更多数据(例如输出应该是什么样的?)

select r.*, 
    case when (floor(visit_dt - register_dt) between 0 and 29) 
         then 'Y' else 'N' 
         end as less_than_30_days
from tst_tbl r;

但那是基于您的示例输出。根据您的查询,您似乎正在尝试查找在过去 30 天内(针对该 ID)具有 any 注册日期的所有访问。如果您更喜欢这样做,这里有一种更简单的方法。

select v.*,
    (select nvl(max('Y'),'N')
      from tst_tbl r
      where r.id = v.id
        and (floor(v.visit_dt - r.register_dt) between 0 and 29))
      as reg_within_30_days
from tst_tbl v;

如果我理解正确,并假设 ID 是唯一标识符,您希望按 (ID, REGISTER_DT) 对行进行分组,并从每个组中仅保留带有 [=14= 的行] >= REGISTER_DT,然后从每个组中 select 最早(最旧)的行 VISIT_DT。如果是这样,这样的事情应该有效:

select (columns you want)
from   (
         select t.* 
              , row_number() over (partition by id, register_dt
                                   order by visit_dt) as rn
         from   tst_tbl t
         where  visit_dt >= register_dt
       )
where  rn = 1
;

试试这个

Select id, last_name, first_name, dob, register_dt, register_loc,
visit_dt
From (
  Select r.id, r.last_name, r.first_name, r.dob, r.register_dt, r.register_loc,
r.visit_dt, r.visit_loc, row_number() over (partition by r.register_dt order by r.visit_dt) r
From tst_tbl r
where register_dt < visit_dt
) x
Where x.r = 1