2016-04-29 3 views
11

I Tabelle unten habenCount Anzahl der aufeinanderfolgende Vorkommen von Werten in der Tabelle

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') 

I aufeinanderfolgende Werte in Spalte name

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

Das Beste, was ich versuchte zählen will, ist:

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

aber es gibt mir nicht erwartetes Ergebnis

Antwort

14

Ein Ansatz ist der Unterschied von Zeilennummern:

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; 

Die Logik ist am einfachsten zu verstehen, wenn Sie die Unterabfrage und Blick auf den Werten der einzelnen Zeilennummer getrennt und dann schauen Sie sich den Unterschied aus.

+1

Wenn 'order by max (id)' hinzugefügt wurde, würde das Ergebnis genau wie in der OP-Post (in der Reihenfolge der Datensätze) aussehen. –

+1

@KingKing, danke für deinen Hinweis. Ja, es macht genau das, was ich brauche. – FLICKER

+0

Warum meine Abfrage gibt mir nicht das Ergebnis, ich erwarte, wenn ich nach Name partitionieren, die Anzahl (*) sollte zurückgesetzt werden, wenn die Werte von Name ändert. Ich schätze es, wenn Sie das erklären. Danke noch einmal. – FLICKER

2

Ich habe rekursive CTE und minimieren die Verwendung von Zeilennummer, vermeiden Sie auch count (*).

Ich denke, es wird eine bessere Leistung, aber in der realen Welt hängt davon ab, was Sie sonst filtern, um die Anzahl der betroffenen Zeilen zu minimieren.

Wenn die ID diskrete Werte hat, wird ein zusätzliches CTE verwendet, um eine kontinuierliche ID zu generieren.

;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

es ist erwähnenswert, dass dies auch nicht funktioniert, wenn die ID diskrete Werte hat, wie zum Beispiel "1,2, ... 9", die Werte sind "1,2,3,5,6,7,8, 9,10' ('4' fehlt). –

+0

Danke @ KingKing, ich habe meinen Fehler korrigiert. – KumarHarsh