【问题标题】:SQL Server iterating through time series dataSQL Server 遍历时间序列数据
【发布时间】:2018-08-22 03:49:47
【问题描述】:

我正在使用 SQL Server,想知道是否可以遍历时间序列数据,直到满足特定条件并基于该标签我在其他表中的数据?

例如,假设我有一个这样的表:

Id  Date       Some_kind_of_event
+--+----------+------------------
1  |2018-01-01|dsdf...
1  |2018-01-06|sdfs...
1  |2018-01-29|fsdfs...
2  |2018-05-10|sdfs...
2  |2018-05-11|fgdf...
2  |2018-05-12|asda...
3  |2018-02-15|sgsd...
3  |2018-02-16|rgw...
3  |2018-02-17|sgs...
3  |2018-02-28|sgs...

我想要得到的是为每个键计算两个相邻事件之间的差异,并找出这两个相邻事件之间是否存在差异> 10天。如果是的话,我想停止对该特定键的迭代并将标签“非活动”,否则“活动”放在我的另一个表中。完成一个键后,我们从另一个开始。

因此,例如 id = 1 将获得标签“非活动”,因为存在两个相差大于 10 天的日期。最终的结果应该是这样的:

Id  Label       
+--+----------+
1  |inactive 
2  |active
3  |inactive 

任何想法如何做到这一点?用 SQL 可以做到吗?

【问题讨论】:

  • 考虑编辑您的问题并添加您迄今为止尝试过的查询,或者可能是您认为正确查询的外观的“伪查询”。
  • 另外,您需要其他表数据的样本,因此我们知道如何将它们联系起来,以及哪种方法最适合您的场景。

标签: sql sql-server database


【解决方案1】:

使用 DBMS 时,您需要摆脱反复思考的想法。相反,你需要尝试和思考。 “不要考虑要对行做什么,而要考虑要对列做什么。”

如果我理解正确,这就是你想要的吗?

CREATE TABLE SomeEvent (ID int, EventDate date, EventName varchar(10));
INSERT INTO SomeEvent
VALUES (1,'20180101','dsdf...'),
       (1,'20180106','sdfs...'),
       (1,'20180129','fsdfs..'),
       (2,'20180510','sdfs...'),
       (2,'20180511','fgdf...'),
       (2,'20180512','asda...'),
       (3,'20180215','sgsd...'),
       (3,'20180216','rgw....'),
       (3,'20180217','sgs....'),
       (3,'20180228','sgs....');
GO
WITH Gaps AS(
    SELECT *,
           DATEDIFF(DAY,LAG(EventDate) OVER (PARTITION BY ID ORDER BY EventDate),EventDate) AS EventGap
    FROM SomeEvent)
SELECT ID,
       CASE WHEN MAX(EventGap) > 10 THEN 'inactive' ELSE 'active' END AS Label
FROM Gaps
GROUP BY ID
ORDER BY ID;

GO
DROP TABLE SomeEvent;
GO

假设您使用的是 SQL Server 2012+,因为它使用 LAG 函数,而 SQL Server 2008 的任何类型支持都不到 12 个月。

【讨论】:

    【解决方案2】:

    试试这个。请注意,将@MyTable 替换为您的实际表格。

    WITH Diffs AS (
    SELECT
        Id
        ,DATEDIFF(DAY,[Date],LEAD([Date],1,0) OVER (ORDER BY [Id], [Date])) Diff
    FROM @MyTable)
    
    SELECT 
        Id
        ,CASE WHEN MAX(Diff) > 10 THEN 'Inactive' ELSE 'Active' END
    FROM Diffs
    GROUP BY Id
    

    【讨论】:

      【解决方案3】:

      只是为了分享另一种方法(没有 CTE)。

      SELECT 
          ID 
      ,   CASE WHEN SUM(TotalDays) = (MAX(CNT) - 1) THEN 'Active' ELSE 'Inactive' END Label
      FROM (
      SELECT 
          ID 
      ,   EventDate
      ,   CASE WHEN DATEDIFF(DAY, EventDate, LEAD(EventDate) OVER(PARTITION BY ID ORDER BY EventDate)) < 10 THEN 1 ELSE 0 END TotalDays
      ,   COUNT(ID) OVER(PARTITION BY ID) CNT
      FROM EventsTable 
      ) D
      GROUP BY ID
      

      该方法是计算每个 ID 有多少条记录,并通过当前下一个日期之间的日期差异(以天为单位)获取 TotalDays,如果差异小于 10 天,则给我 1,否则给我 0 .

      然后比较,如果总天数等于每个 ID 拥有的记录数(减一),则打印 Active,否则打印 Inactive。

      这只是另一种不使用 CTE 的方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-29
        • 2023-04-08
        • 2022-07-26
        • 2010-12-16
        • 1970-01-01
        • 1970-01-01
        • 2022-08-03
        相关资源
        最近更新 更多