【问题标题】:Find next record where status field is different from current查找状态字段与当前字段不同的下一条记录
【发布时间】:2019-07-03 14:34:42
【问题描述】:

我有一个用于记录事件的表。具体有两种类型:ON 和 OFF。

有时会有重叠的日志条目,因为可能有 2 个同时记录的设备。这并不重要,因为最终报告应该 [大部分] 正确地概述 ON -> OFF 时期。

下面是一个示例,第 3 列仅用于说明:它不存在。

ActionTaken    ID   ID_of_next_OFF
Switched ON    1    3
Switched ON    2    6
Switched OFF   3    
Switched ON    4    7
Switched ON    5    8
Switched OFF   6    
Switched OFF   7    
Switched OFF   8    
Switched On    9    10
Switched OFF   10   
Switched On    11   12
Switched OFF   12   

给定前两列,我如何计算第三列?

这不起作用:

SELECT actionTaken, Id, LEAD(Id) 
OVER (PARTITION BY ActionTaken ORDER BY ID) nextConn 
FROM dbo.Events

因为它将 ID_of_Next 基于下一个匹配的 actionTaken 值,而不是下一个替代值。

【问题讨论】:

    标签: sql-server sql-server-2016 data-partitioning lead


    【解决方案1】:

    你是在正确的方式。您只需要'Switched ON' 部分的LEFT JOIN 和相同行号上的'Switched OFF' 部分。

    with Events as (
      select 'Switched ON' as ActionTaken, 1 as ID union all -- 3
      select 'Switched ON', 2 union all -- 6
      select 'Switched OFF', 3 union all
      select 'Switched ON', 4 union all -- 7
      select 'Switched ON', 5 union all -- 8
      select 'Switched OFF', 6 union all
      select 'Switched OFF', 7 union all
      select 'Switched OFF', 8 union all
      select 'Switched On', 9 union all -- 10
      select 'Switched OFF', 10 union all
      select 'Switched On', 11 union all -- 12
      select 'Switched OFF', 12
    ), E as (
      select
        *, row_number() over(partition by ActionTaken order by ID) as rn
      from Events
    )
    select
      a.ActionTaken, a.ID, b.ID
    from E as a
    left join E as b
      on a.ActionTaken = 'Switched ON' and
         b.ActionTaken = 'Switched OFF' and
         a.rn = b.rn
    order by a.ID, a.ActionTaken;
    

    输出:

    +--------------+----+------+
    | ActionTaken  | ID |  ID  |
    +--------------+----+------+
    | Switched ON  |  1 | 3    |
    | Switched ON  |  2 | 6    |
    | Switched OFF |  3 | NULL |
    | Switched ON  |  4 | 7    |
    | Switched ON  |  5 | 8    |
    | Switched OFF |  6 | NULL |
    | Switched OFF |  7 | NULL |
    | Switched OFF |  8 | NULL |
    | Switched On  |  9 | 10   |
    | Switched OFF | 10 | NULL |
    | Switched On  | 11 | 12   |
    | Switched OFF | 12 | NULL |
    +--------------+----+------+
    

    使用SQL Fiddle在线测试。

    【讨论】:

    • 我将接受的答案移至您的答案,因为它更易于实施,并且可以在排名中添加更多字段。
    • 很高兴为您提供帮助。
    【解决方案2】:

    这样的事情应该可以让你到达那里。

    下面我使用了 2 个 CTE 来拆分关闭和打开数据,然后为第一次打开第一次关闭提供排名项,然后我使用联合查询来匹配它们

    declare @Events table (
        ActionTaken nvarchar(25),
        ID int
    );
    
    insert @Events
    values
    
    --ActionTaken    ID   ID_of_next_OFF
    ('Switched ON' ,   1), -- 3
    ('Switched ON' ,   2),-- 6
    ('Switched OFF',   3),    
    ('Switched ON' ,   4),--    7
    ('Switched ON' ,   5),--    8
        ('Switched OFF',   6),    
        ('Switched OFF',   7),    
        ('Switched OFF',   8),    
        ('Switched On' ,   9),--    10
        ('Switched OFF',   10),   
        ('Switched On' ,   11),--   12
        ('Switched OFF',   12);
    
        with onrank as (
        select row_number()over(order by id) ranking, * from @Events where ActionTaken like '%ON')
        , offrank as (
        select row_number()over(order by id) ranking, * from @Events where ActionTaken like '%OFF')
    
        select o.ActionTaken, o.ID, case when o.ranking=f.ranking then cast(f.id as nvarchar(3)) end as Id_next_off
        from onrank o inner join offrank f on o.ranking=f.ranking
        union
        select ActionTaken, ID, '' from offrank
        order by o.ID;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-12
      • 2012-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-08
      相关资源
      最近更新 更多