Question : Count consecutive values in MS SQL Server 2005

I need a query that is optimized that will return the latest number of consecutive values of either A, B or C by personid.

For example, the fields are:

PersonID, mydate, A, B, C

A, B, C will either be NULL or 1.  Also, only one of these can have 1 at a time (the other values will be NULL for each row).  The mydate is not necessarily ordered but we need the latest consecutive count.

Sample Data:

PersonID, mydate, A, B, C
================
1, 2010-04-22, 1, NULL, NULL
1, 2010-04-18, 1, NULL, NULL
1, 2010-04-21, 1, NULL, NULL
2, 2010-04-18, NULL, 1, NULL
1, 2010-04-14, 1, NULL, NULL
1, 2010-04-15, NULL, 1, NULL
2, 2010-04-15, 1, NULL, NULL

Would return:

PersonID, ConsecType, ConsecCount
======================
1, A, 3
2, B, 1

The ConsecType doesn't necessarily need to be the name of the field... perhaps it could use a case statement or something more efficient to identify the existence of that value.

I think MS-SQL 2005 comes with some newer features like ROW_NUMBER, CTE, PARTITION, etc. that may be able to solve this easier.  I've seen many examples out there but none that are easily transferable (at least to me!).  They also seem to deal with consecutive values of two types (usually 0 or 1)... whereas this has 3... or potentially more.  It would be great to come up with a solution in which there could be N types that are of binary value (1 or NULL).

The more efficient the query is for large datasets, the better!

Thanks!

Answer : Count consecutive values in MS SQL Server 2005

sorry b shouldn't have type in the group by...

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
;with base as (
select a.*,row_number() over (partition by (personid) order by mydate desc) as rn
,case when a.a is not null then 'A'
                     when a.b is not null then 'B'
                      else 'C' end as Type
from mytable as a
)
select a.personid,a.type
      ,case a.type when 'A' 
            then case when b.minb < b.minc then b.minb -1
                      when b.minc < b.minb then b.minC -1
                      when b.minb is not null and b.minc is null then b.minb - 1
                      when b.minb is null and b.minc is not null then b.minc -1
                      else b.maxa end
            when 'B'
            then case when b.mina < b.minc then b.mina -1
                      when b.minc < b.mina then b.minC -1
                      when b.mina is not null and b.minc is null then b.mina - 1
                      when b.mina is null and b.minc is not null then b.minc -1
                      else b.maxb end
             else
                 case when b.minb < b.mina then b.minb -1
                      when b.mina < b.minb then b.mina -1
                      when b.minb is not null and b.mina is null then b.minb - 1
                      when b.minb is null and b.mina is not null then b.mina -1
                      else b.maxc end
             end as conseccount
             
  from (select personid,type from base where rn=1) as a
  inner join (select personid
                    ,min(case type when 'A' then rn else null end) as minA
                    ,min(case type when 'B' then rn else null end) as minb
                    ,min(case type when 'C' then rn else null end) as minc
                    ,max(case type when 'A' then rn else null end) as maxA
                    ,max(case type when 'B' then rn else null end) as maxb
                    ,max(case type when 'C' then rn else null end) as maxc  
                from base
                group by personid 
              )as b
    on a.personid=b.personid
   
order by 1
Random Solutions  
 
programming4us programming4us