根据从上一条记录更改的列值选择记录

时间:2016-06-08 14:01:22

标签: sql sql-server

使用Sql Server 2008

所以我有一个名为States的表,它有这样的数据:

DateTime                | skID | TZ | DomID | EventName | SKGrpID | State
--------------------------------------------------------------------------
2016-06-08 09:22:54.010 | 1234 | 1  | 222   | 0         | 4321    | 0
2016-06-08 09:22:54.000 | 1234 | 1  | 222   | 3         | 4321    | 3
2016-06-08 09:21:56.000 | 1234 | 1  | 222   | 8         | 4321    | 4
2016-06-08 09:19:00.000 | 1234 | 1  | 222   | 7         | 4321    | 4
2016-06-08 09:18:58.000 | 1234 | 1  | 222   | 4         | 4321    | 4
2016-06-08 09:13:06.000 | 1234 | 1  | 222   | 6         | 4321    | 6
2016-06-08 09:10:42.000 | 1234 | 1  | 222   | 4         | 4321    | 4
2016-06-08 09:10:40.000 | 1234 | 1  | 222   | 1         | 5555    | 1
2016-06-08 09:00:28.003 | 1234 | 1  | 222   | 1         | 4321    | 1

可以将行记录为接听电话的人的记录。如果国家是'4'这意味着他们正在通电话,如果是其他任何东西,那么他们不是。最古老的记录位于底部。所以9:10:42的第三条记录是通话开始,9:13:06的记录是通话结束(状态从4变为6)。

有时呼叫会持续多个事件。所以在9:18:58的记录中,呼叫开始并持续到记录在9:21:56(状态开始 - > 4,4,4,3< -End)

我想要一个查询以某种方式选择开始记录和结束记录,加入它们并获得持续时间。问题是我不知道如何根据状态从4改为其他东西。我也在努力弄清楚如何选择每个调用的每个开始(开始记录将是状态为4的记录,而前面的记录是其他东西(所以像状态1,4,3,6,4) ,5将是第二个,第5个记录将是呼叫开始,3和6将是呼叫的结束。))

理想的结果就像是

StartTime, EndTime, Duration, skID, TZ, DomID, SKGrpID, StartEvent, StartState, EndEvent, EndState 

我能够通过查询所有行然后制作dicts并匹配调用方式来完成当前在python中的这个,但我想尽可能在​​SQL中做。这种选择甚至可能吗?

2 个答案:

答案 0 :(得分:1)

这是一种方法:

select
  max(case when RN = 1 then DateTime end) as StartTime,
  max(case when RN = 2 then DateTime end) as EndTime,
  max(case when RN = 1 then EventName end) as StartEvent,
  max(case when RN = 2 then EventName end) as EndEvent
from
(
  select
    *,
    row_number() over (partition by CallId order by DateTime) as RN
  from
  (
    select
      *,
      sum(CallStatus) over (order by DateTime) as CallId
    from
    (
      select
        *
      from
      (
        select 
          *,
          lag(CallStatus) over (order by DateTime) as PrevCallStatus
        from
        (
          select 
            DateTime,
            State,
            EventName,
            case when State = 4 then 1 else 0 end as CallStatus
          from #Table1
        ) A
      ) B
      where CallStatus != PrevCallStatus 
    ) C
  ) D
) E
group by CallId

这从最里面的派生表A开始,该表用于分配呼叫状态1/0。表B用于获取CallStatus的先前值,然后使用该值过滤掉具有相同CallStatus的行。因为CallStatus是1/0,所以它可以在运行总计中用于为每个调用计算单独的ID。因为来自它的数据总是包含2行,所以row_number用于为行分配一个数字(1 =开始,2 =结束),然后在最终选择中使用它来分别从开始行和结束行获取数据。

这没有你所有的领域,但至少它应该让你开始:)

这假设您始终拥有呼叫的结束记录,并且仅适用于SQL Server 2012或更高版本。对于旧版本,您需要为运行总计和滞后创建更复杂的内容。很可能光标是最好的选择。

答案 1 :(得分:0)

SELECT 'StartTime'
     , 'EndTime'
     , 'Duration'
     , 'skID'
     , 'TZ'
     , 'DomID'
     , 'SKGrpID'
     , 'StartEvent'
     , 'StartState'
     , 'EndEvent'
     , 'EndState';

如果那不是您的意思,请澄清。 ;-)