3

我有如下数据。在这个我需要找到他们月份的差异应该> = 6的行。逻辑应该是,我们需要从第一行进行比较,直到我们得到月份差异为6的行,然后需要遵循相同的逻辑从新匹配的行开始,然后继续。

我在我的示例数据和预期输出下方添加。

Fromdate    LectureiD   StudentID   Diff Months Expected
1-Oct-13    1102          55586         null
15-Oct-13   1102          55586          0
15-Oct-13   1102          55586          0
4-Apr-14    1102          55586          6
19-Dec-14   1102          55586          8
27-Dec-14   1102          55586          0
14-Jan-15   1102          55586          0
14-Jan-15   1102          55586          0
29-Sep-15   1102          55586          8
1-Oct-13    1102          55557          null
15-Oct-13   1102          55557          0
15-Oct-13   1102          55557          0
4-Apr-14    1102          55557          6
19-Dec-14   1102          55557          8

以下是我在 oracle 中使用解析函数尝试的逻辑。

select lectureid, 
       studentid,
       floor(months_between(fromdate, 
                            lag(fromdate) over (partition by
                                                   lectureid, 
                                                   studentid 
                                                order by fromdate
                                               )
                           )
            ) monthdiff 
 from above_table;

由于滞后函数的默认偏移量为 1,因此它只检查之前的行,因为我上面提到的逻辑在这里无法正常工作,因为需要根据新匹配的行动态检查它们之前的行。所以这里的 o/p 如下所示。

由于这个原因,用星号突出显示的行出错了,因为它只与它的前一行进行比较。

Fromdate    LectureiD   StudentID   Diff Month
1-Oct-13    1102           55586        null
15-Oct-13   1102           55586        0
15-Oct-13   1102           55586        0
*4-Apr-14   1102           55586        5*
19-Dec-14   1102           55586        8
27-Dec-14   1102           55586        0
14-Jan-15   1102           55586        0
14-Jan-15   1102           55586        0
29-Sep-15   1102           55586        8
1-Oct-13    1102           55557        null
15-Oct-13   1102           55557        0
15-Oct-13   1102           55557        0
*4-Apr-14   1102           55557        5*
19-Dec-14   1102           55557        8

这里的任何帮助将不胜感激!!!

4

1 回答 1

2

递归解决方案:

with tmp as (
  select fromdate fd, lectureid lid, studentid sid, null mb,
         row_number() over (partition by lectureid, studentid order by fromdate) rn
    from above_table ),
cte (fd, ld, lid, sid, mb, rn) as (
  select fd, fd, lid, sid, mb, rn from tmp where rn=1
  union all
  select tmp.fd, case when floor(months_between(tmp.fd, cte.ld)) >= 6 
                      then tmp.fd else cte.ld end,
         tmp.lid, tmp.sid, floor(months_between(tmp.fd, cte.ld)), tmp.rn
    from tmp join cte on tmp.lid = cte.lid and tmp.sid = cte.sid and tmp.rn = cte.rn+1)
select to_char(fd, 'yyyy-mm-dd') fromdate, lid lecture, sid student, mb 
  from cte order by sid desc, fd

测试数据和输出:

create table above_table (Fromdate date, LectureiD number(6), StudentID number(6), Diff number(4));
insert into above_table values (date '2013-10-01', 1102, 55586, null);
insert into above_table values (date '2013-10-15', 1102, 55586, 0);
insert into above_table values (date '2013-10-15', 1102, 55586, 0);
insert into above_table values (date '2014-04-04', 1102, 55586, 6);
insert into above_table values (date '2014-12-19', 1102, 55586, 8);
insert into above_table values (date '2014-12-27', 1102, 55586, 0);
insert into above_table values (date '2015-01-14', 1102, 55586, 0);
insert into above_table values (date '2015-01-14', 1102, 55586, 0);
insert into above_table values (date '2015-09-29', 1102, 55586, 8);
insert into above_table values (date '2013-10-01', 1102, 55557, null);
insert into above_table values (date '2013-10-15', 1102, 55557, 0);
insert into above_table values (date '2013-10-15', 1102, 55557, 0);
insert into above_table values (date '2013-10-29', 1102, 55557, 0);
insert into above_table values (date '2014-04-04', 1102, 55557, 6);
insert into above_table values (date '2014-12-19', 1102, 55557, 8);

FROMDATE      LECTURE    STUDENT         MB
---------- ---------- ---------- ----------
2013-10-01       1102      55586            
2013-10-15       1102      55586          0 
2013-10-15       1102      55586          0 
2014-04-04       1102      55586          6 
2014-12-19       1102      55586          8 
2014-12-27       1102      55586          0 
2015-01-14       1102      55586          0 
2015-01-14       1102      55586          0 
2015-09-29       1102      55586          9 
2013-10-01       1102      55557            
2013-10-15       1102      55557          0 
2013-10-15       1102      55557          0 
2013-10-29       1102      55557          0 
2014-04-04       1102      55557          6 
2014-12-19       1102      55557          8

解释:

  1. 子查询tmp只为每个讲座和学生分别枚举行:

    选择fromdate fd,lectureid lid,studentid sid,null mb,row_number() over(按lectureid分区,按fromdate排序studentid)rn

  2. 这一行是递归子查询的“锚” CTE,我们在第一步中取两行编号为 1

    从 tmp 中选择 fd、fd、lid、sid、mb、rn,其中 rn=1

  3. 在这一步中,我使用条件附加“递归成员”tmp.rn = cte.rn+1特别重要的是下面的部分,这里我检查上次记住的日期和当前行的日期之间是否有六个月:

    当 floor(months_between(tmp.fd, cte.ld)) >= 6 然后 tmp.fd else cte.ld end

  4. 最后select是语法的必需部分。


一些有用的链接:

于 2015-12-31T15:42:33.790 回答