2013-03-08 89 views
2

我想知道如果有可能算一个记录计数状态改变

例如值之间变化的数字我有以下数据

| radio | name | state | timestamp   | 
|-------|------|-------|---------------------| 
| 1  | AP1 | down | 2013-03-07 10:00:00 | 
| 1  | AP1 | down | 2013-03-07 10:15:00 | 
| 1  | AP1 | up | 2013-03-07 10:30:00 | 
| 1  | AP1 | down | 2013-03-07 10:45:00 | 
| 1  | AP1 | pend | 2013-03-07 11:00:00 | 
| 1  | AP1 | pend | 2013-03-07 11:15:00 | 
| 1  | AP1 | pend | 2013-03-07 11:30:00 | 
| 1  | AP1 | pend | 2013-03-07 11:45:00 | 

我需要做一个查询呢下面的技巧

| name | S1  | S2  | S3  | S4   | (other time range) | 
| AP1 | A  | A  | B  | A   | C     | 
        \ / \ / \ /
         DETECT  DETECT  DETECT  
          \  \  /
          \------- \ /
             COUNT = 3 <-- this is the number i want 

到目前为止我陷入了基于计数的SQL。

SELECT radio, name, state, COUNT(state) AS count FROM data 
WHERE timestamp BETWEEN '2013-03-07 10:00:00' AND '2013-03-07 11:00:00' 
GROUP BY radio, name, channel 

结果届时将

| radio | name | state | count | 
|-------|------|-------|-------| 
| 1  | AP1 | down | 3  | 
| 1  | AP1 | up | 1  | 
| 1  | AP1 | pend | 1  | 

所以现在的结果将是3行3又名状态变化,但后来我意识到,这是不正确的,因为这个数字 只会告诉我的号码不同的州名,在这种情况下是3。

所以我的问题是这可能在SQL中,或者我需要将结果集拉入循环并通过外部脚本或视图检测更改。

+0

什么版本的SQL Server? – gbn 2013-03-08 09:48:52

+0

mssql版本是2008 R2 – Ponsjuh 2013-03-08 09:53:03

回答

3

您可以使用类似:

with Changes as 
(
    select name 
    , stateChange = case when prev.state is null then 0 
     when sc.state <> prev.state then 1 
     else 0 
     end 
    from data sc 
    outer apply 
    (
     select top 1 prev.state 
     from data prev 
     where sc.timestamp > prev.timestamp 
     and sc.name = prev.name 
     order by prev.timestamp desc 
    ) prev 
) 
select name, stateChanges = sum(stateChange) 
from Changes 
group by name 

SQL Fiddle with demo

另外,在你的问题中,你的数据有点不一致;有时候你会提到AP1有时候AP2。如果上面的查询/提琴不够用,请提供一个更大的数据集。

+0

啊是的这是一个“复制/粘贴错字”:)修复它 – Ponsjuh 2013-03-08 10:38:12

+1

也玩这个,它似乎我现在有一些工作的东西:)做一些最终测试,如果它的工作我会将其标记为解决方案 – Ponsjuh 2013-03-08 10:39:17

+1

工作就像一个魅力!亲爱的伊恩普雷斯顿是我当天的英雄 – Ponsjuh 2013-03-08 11:00:12

2

您可以使用LAG():

SELECT sq.RADIO, 
    sq.NAME, 
    COUNT(CASE WHEN sq.STATE != sq.PREV_STATE THEN 1 ELSE NULL END) CHG_COUNT 
FROM 
    (SELECT 
    td.RADIO, 
    td.NAME, 
    td.STATE, 
    COALESCE(LAG(td.STATE,1) OVER(PARTITION BY td.RADIO, td.NAME ORDER BY td.TIMESTAMP ASC),td.STATE) PREV_STATE 
    FROM DATA td) sq 
GROUP BY sq.RADIO, 
    sq.NAME 
+2

这只适用于版本2012 – Ponsjuh 2013-03-08 10:54:32

+0

正确,我认为它是在早期版本中实现的。在这种情况下,伊恩的建议非常优雅。 – 2013-03-08 11:22:59