【问题标题】:T-SQL Query to Identify Date Ranges when an Event Happens事件发生时用于识别日期范围的 T-SQL 查询
【发布时间】:2018-05-23 14:18:42
【问题描述】:

我正在尝试确定某个组织在我们的“监控”列表中的日期范围。

我的数据如下所示:

OrgCode OrgName           ReviewDate    MonitorList
8000    Organization A    3/6/2014      1
8000    Organization A    6/4/2014      1
8000    Organization A    9/4/2014      1
8000    Organization A    12/4/2014     0
8000    Organization A    3/5/2015      1
8000    Organization A    6/4/2015      1
8000    Organization A    9/16/2015     1
8000    Organization A    12/16/2015    1
8000    Organization A    3/9/2016      1
8000    Organization A    6/2/2016      1
8000    Organization A    9/8/2016      1
8000    Organization A    12/8/2016     1
8000    Organization A    3/9/2017      0
8000    Organization A    6/14/2018     0

我正在寻找的查询输出如下所示:

OrgCode OrgName           MonitorStartDate  MonitorEndDate
8000    Organization A    3/6/2014          12/4/2014
8000    Organization A    3/5/2015          3/9/2017

这个组织,即组织 A,曾两次出现在我们的监控列表中:从 3/6/2014 到 12/4/2014,以及 3/5/2015 到 3/9/2017。

我尝试了几种方法来实现这一点,包括,

  • LEAD()LAG()的变种;并且,
  • GROUP BY OrgCode, OrgName, MonitorList 并将 MonitorStartDate 定义为 MIN(ReviewDate) 并将 MonitorEndDate 定义为 MAX(ReviewDate)

第二种方法没有考虑到这些组织可能多次进入/退出监控列表的事实。我仍然认为LEAD()LAG() 的某些组合可能有效;但是,不是他们自己。

你们能提供的任何指导都会很棒,感谢您的帮助!

【问题讨论】:

    标签: sql tsql sql-server-2012


    【解决方案1】:

    当遇到0lead 时,使用运行总和将行分类为组,重新设置值以获取下一行的日期,因为结束日期必须从遇到的第一个 0 开始。然后在具有必要分组的相应列上使用minmax

    select orgcode,orgname
    ,min(case when monitorlist=1 then reviewdate end) as monitorstartdate
    ,max(next_dt) as monitorenddate
    from (select t.*,
          sum(case when monitorlist=0 then 1 else 0 end) over(partition by orgcode order by reviewdate) as grp,
          lead(reviewdate) over(partition by orgcode order by reviewdate) as next_dt
          from tbl t
         ) t
    group by orgcode,orgname,grp
    having max(cast(monitorlist as int))=1
    

    【讨论】:

    • 此查询不会产生问题中给出的预期结果。
    • @JoeFarrell .. 感谢您指出这一点。查看编辑后的版本,它会起作用。
    • @Vasmi Prabhala 谢谢,这个解决方案正是我想要的。
    【解决方案2】:

    有了这个查询

    select orgcode,orgname,format(min(reviewdate),'M/d/yyyy') as monitorstartdate,format(max(next_dt),'M/d/yyyy') as monitorenddate
    from (select t.*,
       sum(case when monitorlist=0 then 1 else 0 end) 
         over(partition by orgcode order by reviewdate) as grp,
         lead(reviewdate) over(partition by orgcode order by reviewdate) as next_dt
       from tbl t
       ) t
    group by orgcode,orgname,grp,MonitorList
    having MonitorList = 1
    

    结果如下

    orgcode     orgname             monitorstartdate    monitorenddate
    8000        "Organization A"    3/6/2014            12/4/2014
    8000        "Organization A"    3/5/2015            3/9/2017
    

    如果人们想验证,Fiddle 链接是 here

    【讨论】:

      【解决方案3】:

      您可以通过计算每行上或之后 0 的数量来识别组。剩下的只是聚合:

      select orgcode, orgname, min(ReviewDate) as MonitorStartDate,
             coalesce(min(case when monitorlist = 0 then ReviewDate end),
                      max(ReviewDate)
                     ) as MontiroEndDate
      from (select t.*,
                   sum(case when monitorlist = 0 then 1 else 0 end) over (partition by orgcode order by reviewdate desc) as grp             
            from t
           ) t
      group by orgcode, orgname, grp
      having max(monitorlist) = 1;
      

      结束日期的逻辑有点棘手:

      • 是“0”记录的ReviewDate
      • 如果没有,则使用最新的ReviewDate

      Here 是一个演示它的 SQL Fiddle。

      【讨论】:

      • 匿名投反对票是粗鲁的,尤其是在基本可以工作的代码上。注释将有助于注意 group by 被遗漏了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-06
      • 2012-01-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多