【问题标题】:How to create a single record from a group within time frame如何在时间范围内从组中创建单个记录
【发布时间】:2020-06-09 20:20:59
【问题描述】:

请帮助解决以下 SQL 挑战。我得到了包含三列项目编号、开始和结束时间戳的 SQL 服务器表,请参阅下面的示例数据。 要求是在 20 分钟的时间范围内(在下面以粗体突出显示)为相同的 itemno 找到一组事务,然后创建一个新的单行,其开始时间戳从第一行开始,结束时间戳从该数据集中的最后一行开始。 有人可以帮忙吗?

源样本数据:

ItemNo     StartTstp               EndTstp
1100    2018-10-10 5:47:00      2018-10-10 6:28:00
1100    2018-10-10 7:47:00      2018-10-10 7:48:00
1100    2018-10-10 7:48:00      2018-10-10 7:50:00
1100    2018-10-10 7:50:00      2018-10-10 7:53:00
1100    2018-10-10 13:10:00     2018-10-10 13:20:00
1100    2018-10-10 16:10:00     2018-10-10 16:30:00
1101    2018-10-10 9:50:00      2018-10-10 9:53:00

输出:

ItemNo  StartTstp               EndTstp
1100    2018-10-10 5:47:00      2018-10-10 6:28:00
1100    2018-10-10 7:47:00      2018-10-10 7:53:00
1100    2018-10-10 13:10:00     2018-10-10 13:20:00
1100    2018-10-10 16:10:00     2018-10-10 16:30:00
1101    2018-10-10 9:50:00      2018-10-10 9:53:00

谢谢。

screenshots of sample & result

【问题讨论】:

  • 请向我们展示您的尝试,以便我们为您提供帮助。
  • 搜索“差距和岛屿问题”。这是一个很好的起点:red-gate.com/simple-talk/sql/t-sql-programming/…
  • 我们还需要知道您的确切 SQL Server 版本。
  • 嗨,亚历克斯,感谢您的回复。版本是2014。另外,我会阅读并尝试理解“差距和岛屿分析简介”。
  • 嗨,Dale,以我有限的技能,如果在 20 分钟内第一行和最后一行,我只能制作一个单行。大体时间。但是,如果交易在 20 分钟内处于中间位置,我找不到解决方案。就像我提供的例子一样。谢谢。

标签: sql sql-server


【解决方案1】:

根据我对问题的理解,您可以试试这个 CTE:

;WITH cte AS 
(
    SELECT
        t1.ItemNo,
        t1.StartTstp,
        MAX(t2.EndTstp) AS EndTstp
    FROM YourTable AS t1
        JOIN YourTable AS t2 ON
            t1.ItemNo = t2.ItemNo
            AND DATEDIFF(MI, t1.StartTstp, t2.StartTstp) BETWEEN 0 AND 20
    GROUP BY
        t1.ItemNo,
        t1.StartTstp
)
SELECT
    ItemNo,
    MIN(StartTstp) AS StartTstp,
    EndTstp
FROM cte
GROUP BY
    ItemNo,
    EndTstp;

这会产生带有样本数据的预期输出,我在 20 分钟内使用额外的日期集进行了测试,并且输出仍然符合预期。但请注意,这只检查整整 20 分钟之间,如果您想包括秒,则应调整 where 子句。

【讨论】:

    【解决方案2】:

    使用lag() 获取之前的EndTstp。使用此信息确定分组何时开始。开始的累积总和定义了一个组。 . .然后聚合:

    select item, min(StartTstp), max(endTstp)
    from (select t.*,
                 sum(case when prev_endtstp >= StartTstp then 0 else 1 end) over
                     (partition by itemno order by StartTstp) as grp
          from (select t.*,
                       lag(EndTstp) over (partition by itemno order by StartTstp) as prev_endtstp
                from t
               ) t
         ) t
    group by itemno, grp
    

    【讨论】:

      猜你喜欢
      • 2015-04-22
      • 2013-09-14
      • 1970-01-01
      • 1970-01-01
      • 2012-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多