SQL-根据时间戳记录查找结束日期和开始日期

发布于 2025-02-11 11:58:54 字数 1661 浏览 1 评论 0原文

目前,我有下表,我想将其汇总到每个资产_ID状态更改的日志中,其中包括开始和结束日期。

即,如果这是我的数据:

asset_idstatus_idupdate_date
112021-06-29 01:00:00
112021-06-29 04:00:00
132021-06-29 056-29 05:00:00
132021 05:00:31
112021-06-29 05:01:00
112021-06-29 05:08:00
122021-06-06-06-06-06-06-30 12:12:12
12-06-292021-06 -30 12:15:12
122021-07-30 04:12:12

我想将其汇总到:

asset_idstatus_id state_idstart_dateend_date end_date
112021-06-29 01:00:002021-06-29 04: 59:59
132021-06-29 05:00:002021-06-29 05:00:59
112021-06-29 05:01:002021-06-06-06-30 12:12:11
122021 -06-30 12:12:122099-12-31 00:00:0

我找到了类似的建议解决方案,但是它们都不包括实际的状态_ID,而end_date直到下一个行开始时间才包括时间减去第二或分钟,即获取列表从数据表的开始和结束值

Currently I have the following table, and I want to aggregate it to some kind of a log of the status changes for each asset_id, that will include a start and end date.

ie, If this is my data:

Asset_IdStatus_IdUpdate_Date
112021-06-29 01:00:00
112021-06-29 04:00:00
132021-06-29 05:00:00
132021-06-29 05:00:31
112021-06-29 05:01:00
112021-06-29 05:08:00
122021-06-30 12:12:12
122021-06-30 12:15:12
122021-07-30 04:12:12

I would like to aggregate it to:

Asset_IdStatus_IdStart_dateEnd_Date
112021-06-29 01:00:002021-06-29 04:59:59
132021-06-29 05:00:002021-06-29 05:00:59
112021-06-29 05:01:002021-06-30 12:12:11
122021-06-30 12:12:122099-12-31 00:00:0

I've found similar proposed solutions, but none of them included the actual status_id and the end_date didn't included the time until the next row start time minus a second or minute, ie Get list with start and end values from table of datetimes

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

方觉久 2025-02-18 11:58:54

请尝试以下解决方案。

sql

DECLARE @tbl TABLE (Asset_Id INT, Status_Id INT, Update_Date DATETIME);
INSERT @tbl (Asset_Id, Status_Id, Update_Date) VALUES
(1, 1, '2021-06-29 01:00:00'),
(1, 1, '2021-06-29 04:00:00'),
(1, 3, '2021-06-29 05:00:00'),
(1, 3, '2021-06-29 05:00:31'),
(1, 1, '2021-06-29 05:01:00'),
(1, 1, '2021-06-29 05:08:00'),
(1, 2, '2021-06-30 12:12:12'),
(1, 2, '2021-06-30 12:15:12'),
(1, 2, '2021-07-30 04:12:12');

;WITH rs AS
(
    SELECT * 
        , series = status_id + ROW_NUMBER() OVER (ORDER BY Update_Date ASC) - 
            ROW_NUMBER() OVER (PARTITION BY Asset_ID, Status_Id ORDER BY Update_Date ASC)
    FROM @tbl
)
SELECT Asset_Id, Status_Id, MIN(Update_Date) AS Start_date, MAX(rs.Update_Date) AS End_Date
FROM rs
GROUP BY Asset_Id, Status_Id, series
ORDER BY MIN(Update_Date) ASC;

sql#2

满足以下内容

end_date直到下一行开始时间才包括时间
减去第二个

;WITH rs AS
(
    SELECT * 
        , series = status_id + ROW_NUMBER() OVER (ORDER BY Update_Date ASC) - 
            ROW_NUMBER() OVER (PARTITION BY Asset_Id, Status_Id ORDER BY Update_Date ASC)
        , DATEADD(SECOND,-1, LEAD(Update_Date,1) OVER (ORDER BY Update_Date ASC)) AS end_date
    FROM @tbl
)
SELECT Asset_Id, Status_Id, MIN(rs.Update_Date) AS Start_date, MAX(COALESCE(rs.end_date,'2099-12-31')) AS End_Date
FROM rs
GROUP BY Asset_Id, Status_Id, series
ORDER BY MIN(rs.Update_Date) ASC;

输出

+----------+-----------+-------------------------+-------------------------+
| Asset_Id | Status_Id |       Start_date        |        End_Date         |
+----------+-----------+-------------------------+-------------------------+
|        1 |         1 | 2021-06-29 01:00:00.000 | 2021-06-29 04:00:00.000 |
|        1 |         3 | 2021-06-29 05:00:00.000 | 2021-06-29 05:00:31.000 |
|        1 |         1 | 2021-06-29 05:01:00.000 | 2021-06-29 05:08:00.000 |
|        1 |         2 | 2021-06-30 12:12:12.000 | 2021-07-30 04:12:12.000 |
+----------+-----------+-------------------------+-------------------------+

输出#2

+----------+-----------+-------------------------+-------------------------+
| Asset_Id | Status_Id |       Start_date        |        End_Date         |
+----------+-----------+-------------------------+-------------------------+
|        1 |         1 | 2021-06-29 01:00:00.000 | 2021-06-29 04:59:59.000 |
|        1 |         3 | 2021-06-29 05:00:00.000 | 2021-06-29 05:00:59.000 |
|        1 |         1 | 2021-06-29 05:01:00.000 | 2021-06-30 12:12:11.000 |
|        1 |         2 | 2021-06-30 12:12:12.000 | 2099-12-31 00:00:00.000 |
+----------+-----------+-------------------------+-------------------------+

Please try the following solution.

SQL

DECLARE @tbl TABLE (Asset_Id INT, Status_Id INT, Update_Date DATETIME);
INSERT @tbl (Asset_Id, Status_Id, Update_Date) VALUES
(1, 1, '2021-06-29 01:00:00'),
(1, 1, '2021-06-29 04:00:00'),
(1, 3, '2021-06-29 05:00:00'),
(1, 3, '2021-06-29 05:00:31'),
(1, 1, '2021-06-29 05:01:00'),
(1, 1, '2021-06-29 05:08:00'),
(1, 2, '2021-06-30 12:12:12'),
(1, 2, '2021-06-30 12:15:12'),
(1, 2, '2021-07-30 04:12:12');

;WITH rs AS
(
    SELECT * 
        , series = status_id + ROW_NUMBER() OVER (ORDER BY Update_Date ASC) - 
            ROW_NUMBER() OVER (PARTITION BY Asset_ID, Status_Id ORDER BY Update_Date ASC)
    FROM @tbl
)
SELECT Asset_Id, Status_Id, MIN(Update_Date) AS Start_date, MAX(rs.Update_Date) AS End_Date
FROM rs
GROUP BY Asset_Id, Status_Id, series
ORDER BY MIN(Update_Date) ASC;

SQL #2

To satisfy the following

the end_date didn't included the time until the next row start time
minus a second

;WITH rs AS
(
    SELECT * 
        , series = status_id + ROW_NUMBER() OVER (ORDER BY Update_Date ASC) - 
            ROW_NUMBER() OVER (PARTITION BY Asset_Id, Status_Id ORDER BY Update_Date ASC)
        , DATEADD(SECOND,-1, LEAD(Update_Date,1) OVER (ORDER BY Update_Date ASC)) AS end_date
    FROM @tbl
)
SELECT Asset_Id, Status_Id, MIN(rs.Update_Date) AS Start_date, MAX(COALESCE(rs.end_date,'2099-12-31')) AS End_Date
FROM rs
GROUP BY Asset_Id, Status_Id, series
ORDER BY MIN(rs.Update_Date) ASC;

Output

+----------+-----------+-------------------------+-------------------------+
| Asset_Id | Status_Id |       Start_date        |        End_Date         |
+----------+-----------+-------------------------+-------------------------+
|        1 |         1 | 2021-06-29 01:00:00.000 | 2021-06-29 04:00:00.000 |
|        1 |         3 | 2021-06-29 05:00:00.000 | 2021-06-29 05:00:31.000 |
|        1 |         1 | 2021-06-29 05:01:00.000 | 2021-06-29 05:08:00.000 |
|        1 |         2 | 2021-06-30 12:12:12.000 | 2021-07-30 04:12:12.000 |
+----------+-----------+-------------------------+-------------------------+

Output #2

+----------+-----------+-------------------------+-------------------------+
| Asset_Id | Status_Id |       Start_date        |        End_Date         |
+----------+-----------+-------------------------+-------------------------+
|        1 |         1 | 2021-06-29 01:00:00.000 | 2021-06-29 04:59:59.000 |
|        1 |         3 | 2021-06-29 05:00:00.000 | 2021-06-29 05:00:59.000 |
|        1 |         1 | 2021-06-29 05:01:00.000 | 2021-06-30 12:12:11.000 |
|        1 |         2 | 2021-06-30 12:12:12.000 | 2099-12-31 00:00:00.000 |
+----------+-----------+-------------------------+-------------------------+
萌︼了一个春 2025-02-18 11:58:54

我遵循了Larnu在OP评论中的建议,并将SQL脚本调整到下面,这是我所需要的

WITH EndsMarked
AS
    (SELECT F.Asset_Id
          , F.Status_Id
          , F.Creation_Date
          , CASE
                 WHEN LAG(F.Status_Id, 1) OVER (PARTITION BY F.Asset_Id
                                                ORDER BY F.Asset_Id
                                                       , F.Creation_Date
                                               ) IS NULL
                      AND ROW_NUMBER() OVER (PARTITION BY F.Asset_Id
                                             ORDER BY F.Creation_Date
                                            ) = 1 THEN 1
                 WHEN LAG(F.Status_Id, 1) OVER (PARTITION BY F.Asset_Id
                                                ORDER BY F.Asset_Id
                                                       , F.Creation_Date
                                               ) <> LAG(F.Status_Id, 0) OVER (PARTITION BY F.Asset_Id
                                                                              ORDER BY F.Asset_Id
                                                                                     , F.Creation_Date
                                                                             ) THEN 1
                 ELSE 0
            END AS IS_START
          , CASE
                 WHEN LEAD(F.Status_Id, 1) OVER (PARTITION BY F.Asset_Id
                                                 ORDER BY F.Asset_Id
                                                        , F.Creation_Date
                                                ) IS NULL
                      AND ROW_NUMBER() OVER (PARTITION BY F.Asset_Id
                                             ORDER BY F.Creation_Date DESC
                                            ) = 1 THEN 1
                 WHEN LEAD(F.Status_Id, 0) OVER (PARTITION BY F.Asset_Id
                                                 ORDER BY F.Asset_Id
                                                        , F.Creation_Date
                                                ) <> LEAD(F.Status_Id, 1) OVER (PARTITION BY F.Asset_Id
                                                                                ORDER BY F.Asset_Id
                                                                                       , F.Creation_Date
                                                                               ) THEN 1
                 ELSE 0
            END AS IS_END
     FROM
            (
            SELECT mrsabda.Assets_AssetId        AS Asset_Id
                 , mrsabda.CreationDate          AS Creation_Date
                 , mrsabda.Assets_Asset_StatusId AS Status_Id
            --,[Aantal Facturen]
            FROM   MRR.MRR_Round_Status_Audit_Buildup_Dim_Asset AS mrsabda
            ) AS F )
   , GroupsNumbered
AS
    (SELECT EndsMarked.Asset_Id
          , EndsMarked.Status_Id
          , EndsMarked.Creation_Date
          , EndsMarked.IS_START
          , EndsMarked.IS_END
          , COUNT(   CASE
                          WHEN EndsMarked.IS_START = 1 THEN 1
                     END
                 ) OVER (ORDER BY EndsMarked.Asset_Id
                                , EndsMarked.Creation_Date
                        ) AS GroupNum
     FROM   EndsMarked
     WHERE  EndsMarked.IS_START = 1
            OR EndsMarked.IS_END = 1)
SELECT   a.Asset_Id
       , a.Status_Id
       , a.GROUP_START                                                                                   AS Start_Date
       , DATEADD(SECOND, -1, LEAD(a.GROUP_START, 1, '2099-12-31 00:00:01') OVER (ORDER BY a.GROUP_START)) AS End_Date
FROM
         (
         SELECT   GroupsNumbered.Asset_Id
                , GroupsNumbered.Status_Id
                , MIN(GroupsNumbered.Creation_Date) AS GROUP_START
                , MAX(GroupsNumbered.Creation_Date) AS GROUP_END
         FROM     GroupsNumbered
         GROUP BY GroupsNumbered.Asset_Id
                , GroupsNumbered.Status_Id
                , GroupsNumbered.GroupNum
         ) AS a
GROUP BY a.Asset_Id
       , a.Status_Id
       , a.GROUP_START

I've followed Larnu recommendation on the op comment and adjusted the SQL script to the below, this is provided me what I need

WITH EndsMarked
AS
    (SELECT F.Asset_Id
          , F.Status_Id
          , F.Creation_Date
          , CASE
                 WHEN LAG(F.Status_Id, 1) OVER (PARTITION BY F.Asset_Id
                                                ORDER BY F.Asset_Id
                                                       , F.Creation_Date
                                               ) IS NULL
                      AND ROW_NUMBER() OVER (PARTITION BY F.Asset_Id
                                             ORDER BY F.Creation_Date
                                            ) = 1 THEN 1
                 WHEN LAG(F.Status_Id, 1) OVER (PARTITION BY F.Asset_Id
                                                ORDER BY F.Asset_Id
                                                       , F.Creation_Date
                                               ) <> LAG(F.Status_Id, 0) OVER (PARTITION BY F.Asset_Id
                                                                              ORDER BY F.Asset_Id
                                                                                     , F.Creation_Date
                                                                             ) THEN 1
                 ELSE 0
            END AS IS_START
          , CASE
                 WHEN LEAD(F.Status_Id, 1) OVER (PARTITION BY F.Asset_Id
                                                 ORDER BY F.Asset_Id
                                                        , F.Creation_Date
                                                ) IS NULL
                      AND ROW_NUMBER() OVER (PARTITION BY F.Asset_Id
                                             ORDER BY F.Creation_Date DESC
                                            ) = 1 THEN 1
                 WHEN LEAD(F.Status_Id, 0) OVER (PARTITION BY F.Asset_Id
                                                 ORDER BY F.Asset_Id
                                                        , F.Creation_Date
                                                ) <> LEAD(F.Status_Id, 1) OVER (PARTITION BY F.Asset_Id
                                                                                ORDER BY F.Asset_Id
                                                                                       , F.Creation_Date
                                                                               ) THEN 1
                 ELSE 0
            END AS IS_END
     FROM
            (
            SELECT mrsabda.Assets_AssetId        AS Asset_Id
                 , mrsabda.CreationDate          AS Creation_Date
                 , mrsabda.Assets_Asset_StatusId AS Status_Id
            --,[Aantal Facturen]
            FROM   MRR.MRR_Round_Status_Audit_Buildup_Dim_Asset AS mrsabda
            ) AS F )
   , GroupsNumbered
AS
    (SELECT EndsMarked.Asset_Id
          , EndsMarked.Status_Id
          , EndsMarked.Creation_Date
          , EndsMarked.IS_START
          , EndsMarked.IS_END
          , COUNT(   CASE
                          WHEN EndsMarked.IS_START = 1 THEN 1
                     END
                 ) OVER (ORDER BY EndsMarked.Asset_Id
                                , EndsMarked.Creation_Date
                        ) AS GroupNum
     FROM   EndsMarked
     WHERE  EndsMarked.IS_START = 1
            OR EndsMarked.IS_END = 1)
SELECT   a.Asset_Id
       , a.Status_Id
       , a.GROUP_START                                                                                   AS Start_Date
       , DATEADD(SECOND, -1, LEAD(a.GROUP_START, 1, '2099-12-31 00:00:01') OVER (ORDER BY a.GROUP_START)) AS End_Date
FROM
         (
         SELECT   GroupsNumbered.Asset_Id
                , GroupsNumbered.Status_Id
                , MIN(GroupsNumbered.Creation_Date) AS GROUP_START
                , MAX(GroupsNumbered.Creation_Date) AS GROUP_END
         FROM     GroupsNumbered
         GROUP BY GroupsNumbered.Asset_Id
                , GroupsNumbered.Status_Id
                , GroupsNumbered.GroupNum
         ) AS a
GROUP BY a.Asset_Id
       , a.Status_Id
       , a.GROUP_START
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文