【问题标题】:SQL: Pulling first and last date entry date from a series with repeated entries, separating blocks that aren't continuousSQL:从具有重复条目的系列中提取第一个和最后一个日期输入日期,分隔不连续的块
【发布时间】:2021-09-18 23:52:06
【问题描述】:

为标题道歉 - 想不出一个符合我想做的事!

所以我有包含这些房间的 ID 值、房间和进入/退出日期/时间的数据。有时数据输入不是很好,ID 退出并进入同一个房间,创建一个中断,这是我想删除的,以便获得他们在房间中的连续时间。

当只有一个“块”日期/时间使用时,我可以做到这一点

RANK() (PARTITION BY TicketNo, Room ORDER BY Entered_DTTM asc) as [RankbyEntered_DTTM]
and
RANK() (PARTITION BY TicketNo, Room ORDER BY Exit_DTTM desc) as [RankbyExit_DTTM]

在 2 个子查询中获取最早进入和最晚退出,然后使用 Rank = 1 将它们连接回原始表,但如果一个 ID 有 2 个单独的句点,则它不考虑在中间。

数据的一个例子(我曾经在中途得到的排名)是这样的:

TicketNo Room Entered_DTTM Exit_DTTM RankbyEntered_DTTM RankbyExit_DTTM
65768 A 05/01/2019 18:55 05/01/2019 19:30 1 1
65768 B 05/01/2019 19:30 05/01/2019 19:35 1 5
65768 B 05/01/2019 19:35 05/01/2019 20:18 2 4
65768 C 05/01/2019 20:18 05/01/2019 20:34 1 1
65768 D 05/01/2019 20:34 05/01/2019 20:59 1 1
65768 E 05/01/2019 20:59 05/01/2019 21:15 1 2
65768 E 05/01/2019 21:15 05/01/2019 21:20 2 1
65768 B 05/01/2019 21:20 05/01/2019 21:22 3 3
65768 B 05/01/2019 21:22 05/01/2019 21:23 4 2
65768 B 05/01/2019 21:23 05/01/2019 21:37 5 1

这就是我想要的方式:

TicketNo Room Entered_DTTM Exit_DTTM
65768 A 05/01/2019 18:55 05/01/2019 19:30
65768 B 05/01/2019 19:30 05/01/2019 20:18
65768 C 05/01/2019 20:18 05/01/2019 20:34
65768 D 05/01/2019 20:34 05/01/2019 20:59
65768 E 05/01/2019 20:59 05/01/2019 21:20
65768 B 05/01/2019 21:20 05/01/2019 21:37

但我无法为房间 B 买这个:

TicketNo Room Entered_DTTM Exit_DTTM
65768 B 05/01/2019 19:30 05/01/2019 21:37

任何帮助将不胜感激!

【问题讨论】:

  • 搜索“差距和孤岛”问题。还有很多用它标记的问题:[gaps-and-islands]

标签: sql sql-server date tsql grouping


【解决方案1】:

您的数据完美贴图。如果是这种情况,那么您可以使用“two-lag()”方法:

select ticket_no, room, entered_dttm,
       lead(entered_dttm, 1, max_exit_dttm) over (partition by ticket_no order by entered_dttm) as exit_dttm
from (select t.*,
             lag(room) over (partition by ticket_no order by entered_dttm) as prev_room,
             max(exit_dttm) over (partition by ticket_no) as max_exit_dttm
      from t
     ) t
where prev_room is null or prev_room <> room;

与其他类型的间隙和孤岛问题不同,这提供了一种无需聚合的解决方案,这可能是性能上的胜利。当然,这取决于您的示例数据中完美平铺的时间框架。

【讨论】:

    【解决方案2】:

    另一种替代方法是使用 SUM 聚合在 TicketNo 值内构建组,然后在其中找到 MIN/MAX 日期:

    CREATE TABLE #tmp (TicketNo int,Room varchar(4), Entered_DTTM datetime, Exit_DTTM datetime)
    INSERT INTO #tmp VALUES
    (65768,'A','05/01/2019 18:55','05/01/2019 19:30'),
    (65768,'B','05/01/2019 19:30','05/01/2019 19:35'),
    (65768,'B','05/01/2019 19:35','05/01/2019 20:18'),
    (65768,'C','05/01/2019 20:18','05/01/2019 20:34'),
    (65768,'D','05/01/2019 20:34','05/01/2019 20:59'),
    (65768,'E','05/01/2019 20:59','05/01/2019 21:15'),
    (65768,'E','05/01/2019 21:15','05/01/2019 21:20'),
    (65768,'B','05/01/2019 21:20','05/01/2019 21:22'),
    (65768,'B','05/01/2019 21:22','05/01/2019 21:23'),
    (65768,'B','05/01/2019 21:23','05/01/2019 21:37')
    
    SELECT TicketNo, Room, MIN(Entered_DTTM) Entered_DTTM, MAX(Exit_DTTM) Exit_DTTM
    FROM
    (
        SELECT *, SUM(CASE WHEN Room <> LG_PREV OR LG_PREV IS NULL THEN 1 END) OVER(ORDER BY Entered_DTTM) Grp
        FROM
        (
            select *,  LAG(Room,1) OVER(PARTITION BY TicketNo ORDER BY Entered_DTTM) LG_PREV
            from #tmp
        ) T
    ) O
    GROUP BY GRP, TicketNo,Room
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-14
      • 1970-01-01
      • 1970-01-01
      • 2022-10-25
      • 1970-01-01
      • 2012-05-29
      • 2013-02-09
      • 1970-01-01
      相关资源
      最近更新 更多