【问题标题】:Finding difference in months using analytical function in oracle使用 oracle 中的分析函数查找月份的差异
【发布时间】:2015-12-31 11:56:00
【问题描述】:

我有如下数据。在这个我需要找到他们月份的差异应该> = 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

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

【问题讨论】:

  • 我已经在上面提到了正确的数据集..我刚刚提到了最后一个数据集以突出显示哪里出错了..Thx
  • 对不起,我相信它没有很好地对齐。最后一列不是学生 id 它是 o/p 列(diffmonth)
  • 对于*4-Apr-14 1102 55586 5*学生1102那一行,如果第一次约会也是15-Oct-13会是什么结果
  • 当上一行匹配 >=6 规则时,为什么 19-Dec-14 1102 55586 应该是 8?
  • @JorgeCampos - 如果第一个日期也是 2013 年 10 月 15 日,那么它应该是 5,因为他们几个月的差异将是 5

标签: sql oracle oracle11g lag lead


【解决方案1】:

递归解:

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 只为每个讲座和学生分别枚举行:

    select fromdate fd、lectureid lid、studentid sid、null mb、 row_number() over (partition by Lectureid, studentid order by fromdate) 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 then tmp.fd else cte.ld end

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


一些有用的链接:

【讨论】:

  • 是否可以通过先验连接来做同样的事情。如果可以,请指导我。
  • @arunb2w - 我认为我们不能在这里使用connect by。递归查询提供了更多的可能性,我用来计算临时列 ld 和结果 - 列 mb (几个月之间)。我看不出如何在connect by 中做到这一点。 Prior 还不够。递归查询的替代方法是 PLSQL 或 MODEL 子句(不确定)。
  • 我在这里对这个话题有几个问题。你介意为我澄清这些吗?我在这里创建了聊天室。 chat.stackoverflow.com/rooms/101205/…有空请加入
  • 你能帮忙吗??
  • 请给我一些链接以更好地理解这一点
猜你喜欢
  • 2023-04-04
  • 2013-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-17
  • 1970-01-01
相关资源
最近更新 更多