【问题标题】:SQL: Get date difference between rows in the same column [duplicate]SQL:获取同一列中的行之间的日期差异[重复]
【发布时间】:2020-02-06 21:50:24
【问题描述】:

我正在尝试创建报告,这是我的输入数据。

  Stage  Name         Date
    1     x     12/05/2019 10:00:03
    1     x     12/05/2019 10:05:01
    1     y     12/06/2019 12:00:07
    2     x     12/06/2019 13:12:03
    2     x     12/06/2019 13:23:00
    1     y     12/08/2019 16:00:07
    2     x     12/09/2019 09:17:59  

这是我想要的输出。

  Stage  Name       DateFrom               DateTo            DateDiff
    1     x     12/05/2019 10:00:03    12/06/2019 12:00:07        1
    1     y     12/06/2019 12:00:07    12/06/2019 13:12:03        0
    2     x     12/06/2019 13:12:03    12/08/2019 16:00:07        2
    1     y     12/08/2019 16:00:07    12/09/2019 09:17:59        1

我不能在阶段和名称上使用 group by 子句,因为它会将我输入的第 3 行和第 6 行分组。我尝试将表连接到自身,但没有得到想要的结果。这在 SQL 中甚至可能吗?任何想法都会有所帮助。我正在使用 Microsoft SQL Server。

【问题讨论】:

  • 这是一个典型的“差距和岛屿”问题,其中岛分区由元组(阶段,名称)定义。应作为副本关闭。
  • @TheImpaler,我同意,但我没有一个很好的规范空白和孤岛问题可用作基础。我不认为你有一个书签?

标签: sql sql-server tsql gaps-and-islands


【解决方案1】:

这是间隙和孤岛问题的变体。您想将相邻行的组组合在一起(即具有相同的阶段和名称);但您想使用下一组的开始日期作为当前组的结束日期。

这是一种方法:

select 
    stage,
    name,
    min(date) date_from,
    lead(min(date)) over(order by min(date)) date_to,
    datediff(day, min(date), lead(min(date)) over(order by min(date))) date_diff 
from (
    select
        t.*,
        row_number() over(order by date) rn1,
        row_number() over(partition by stage, name order by date) rn2
    from mytable t
) t
group by stage, name, rn1 - rn2
order by date_from

Demo on DB Fiddle

舞台 |姓名 | date_from | date_to |日期差异 ----: | :--- | :----------------- | :----------------- | --------: 1 | x | 12/05/2019 10:00:03 | 12/06/2019 12:00:07 | 1 1 |是 | 12/06/2019 12:00:07 | 12/06/2019 13:12:03 | 0 2 | x | 12/06/2019 13:12:03 | 2019 年 12 月 8 日 16:00:07 | 2 1 |是 | 2019 年 12 月 8 日 16:00:07 | 2019 年 12 月 9 日 09:17:59 | 1 2 | x | 2019 年 12 月 9 日 09:17:59 | |

请注意,这不会完全产生您显示的结果:在结果集的末尾有一个附加的待处理记录,它代表“正在进行的”记录系列。如果需要,您可以通过嵌套查询将其过滤掉:

select *
from ( 
    select 
        stage,
        name,
        min(date) date_from,
        lead(min(date)) over(order by min(date)) date_to,
        datediff(day, min(date), lead(min(date)) over(order by min(date))) date_diff
    from (
        select
            t.*,
            row_number() over(order by date) rn1,
            row_number() over(partition by stage, name order by date) rn2
        from mytable t
    ) t
    group by stage, name, rn1 - rn2
) t 
where date_to is not null
order by date_from

【讨论】:

    【解决方案2】:

    间隙和岛屿问题的变体,但它有一个非常简单的解决方案。

    只需保留行具有不同阶段或名称的每一行。然后使用lead() 获取下一个日期。基本思路如下:

    select t.stage, t.name, t.date as datefrom
           lead(t.date) over (order by t.date) as dateto,
           datediff(day, t.date, lead(t.date) over (order by t.date)) as diff
    from (select t.*,
                 lag(date) over (partition by stage, name order by date) as prev_sn_date,
                 lag(date) over (order by date) as prev_date
          from t
         ) t
    where prev_sn_date <> prev_date or prev_sn_date is null;
    

    如果真的要过滤掉最后一行,还需要多一步;我不确定这是否可取。

    【讨论】:

      猜你喜欢
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 2014-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-25
      • 1970-01-01
      相关资源
      最近更新 更多