2016-04-29 40 views
11

ho sotto la tabellaConte il numero di presenza consecutiva dei valori nella tabella

create table #t (Id int, Name char) 

insert into #t values 
(1, 'A'), 
(2, 'A'), 
(3, 'B'), 
(4, 'B'), 
(5, 'B'), 
(6, 'B'), 
(7, 'C'), 
(8, 'B'), 
(9, 'B') 

Voglio contare valori consecutivi nella colonna nome

+------+------------+ 
| Name | Repetition | 
+------+------------+ 
| A |   2 | 
| B |   4 | 
| C |   1 | 
| B |   2 | 
+------+------------+ 

La cosa migliore che ho provato è:

select Name 
, COUNT(*) over (partition by Name order by Id) AS Repetition 
from #t 
order by Id 

ma non mi dà risultato previsto

risposta

14

Un approccio è la differenza di numeri di riga:

select name, count(*) 
from (select t.*, 
      (row_number() over (order by id) - 
       row_number() over (partition by name order by id) 
      ) as grp 
     from t 
    ) t 
group by grp, name; 

La logica è semplice da capire se si esegue la subquery e guardare i valori di ogni numero di riga separatamente e poi guardare la differenza.

+1

Con "ordine per max (id)" aggiunto, il risultato apparirebbe esattamente come nel post dell'OP (che implica l'ordine dei record). –

+1

@KingKing, grazie per il tuo suggerimento. Sì, lo rende esattamente come quello di cui ho bisogno. – FLICKER

+0

Perché la mia query non mi dà il risultato, mi aspetto che quando partirò per nome, il conteggio (*) debba essere ripristinato quando i valori di Name cambiano. Apprezzo se lo spieghi. Grazie ancora. – FLICKER

2

Ho utilizzato CTE ricorsivo e ridurre al minimo l'uso di numero_riga, evitare anche il conteggio (*).

Penso che funzionerà meglio, ma nel mondo reale dipende da quale altro filtro viene inserito per minimizzare il numero di righe interessate.

Se l'ID ha valori discreti, verrà utilizzato un CTE aggiuntivo per generare un ID continuo.

;With CTE2 as 
(
select ROW_NUMBER()over(order by id) id, name,1 Repetition ,1 Marker from @t 
) 
, CTE as 
(
select top 1 cast(id as int) id, name,1 Repetition ,1 Marker from CTE2 order by id 

union all 

select a.id, a.name 
, case when a.name=c.name then Repetition +1 else 1 end 
, case when a.name=c.name then c.Marker else Marker+1 end 
from @t a 
inner join CTE c on a.id=c.id+1 

) 
,CTE1 as 
(select *,ROW_NUMBER()over(partition by marker order by id desc)rn from cte c 
) 
select Name,Repetition from cte1 where rn=1 
+0

vale la pena notare che anche questo non funziona se l'id ha valori discreti, come invece di '1,2, ... 9', i valori sono' 1,2,3,5,6,7,8, 9,10' (manca il '4'). –

+0

Grazie @ KingKing, ho corretto il mio errore. – KumarHarsh