2009-08-10 17 views
3

Ich habe eine Frage zur Datenanalyse, die ich leicht mit etwas T-SQL oder etwas Scripting lösen könnte, aber ich fragte mich, ob es eine clevere SQL-Lösung gab. Das Problem ist, dass es ein wenig mit der Zeilenunabhängigkeitsannahme von SQL etwas verwechselt.Zählen aufeinander folgender Duplikate mit SQL

Ich habe eine Tabelle, die zum Beispiel mit einem Benutzer und geordnet nach Vorlage, zugeordnet Name-Wert-Paaren besteht:

 
ID  USERID VARIABLE  VALUE SUBMITTED 
3115 2287 votech05 2 2009-02-02 15:34:00 
3116 2287 comcol05 1 2009-02-02 15:34:00 
3117 2287 fouryr05 1 2009-02-02 15:35:00 
3118 2287 none05   2 2009-02-02 15:35:00 
3119 2287 ocol1_05 2 2009-02-02 15:44:00 
3120 2287 disnone   2 2009-02-02 15:45:00 
3121 2287 dissense 2 2009-02-02 15:49:00 
3122 2287 dismobil 3 2009-02-02 15:51:00 
3123 2287 dislearn 3 2009-02-02 15:51:00 
3124 2287 disment   3 2009-02-02 15:52:00 
3125 2287 disother 2 2009-02-02 15:55:00 
3126 2287 disrefus 7 2009-02-02 15:58:00 

ich in der Lage sein möchte, den Wert und die Zählung des größten zu bestimmen Gruppe identischer Werte (wenn die Daten geordnet sind, der ID-Primärschlüssel). Also, für das obige Beispiel, weil ich vier Wert = 2 in der Reihenfolge erscheinen, und nur drei Wert = 3, wurde ich melden:

 
USERID  VALUE  COUNT 
2287  2   4 

für den jeweiligen Benutzer.

Auch dies wäre ziemlich schnell mit anderen Tools möglich, aber da der Datensatz ziemlich groß ist (etwa 75 Millionen Datensätze) und sich häufig ändert, wäre es schön, dieses Problem mit einer Abfrage lösen zu können . Ich arbeite mit SQL Server 2005.

+0

Guter Titel bearbeiten, Brian. Vielen Dank.Ich arbeite für einen Umfrageforscher, und sein Jargon hat die Art und Weise beeinflusst, wie ich über das Problem nachdachte. –

Antwort

3

(Herausgegeben nach Kommentar)

Sie können dies tun, indem eine „Kopf“ Nummer, die jede Gruppe von aufeinanderfolgenden Werten zuweisen. Danach wählen Sie die Kopfnummer für jede Zeile aus und führen ein Aggregat pro Kopf durch.

Hier ist ein Beispiel, mit CTE zur besseren Lesbarkeit:

WITH 
OrderedTable as (
    select value, rownr = row_number() over (order by userid, id) 
    from YourTable 
    where userid = 2287 
), 
Heads as (
    select cur.rownr, CurValue = cur.value 
    , headnr = row_number() over (order by cur.rownr) 
    from OrderedTable cur 
    left join OrderedTable prev on cur.rownr = prev.rownr+1 
    where IsNull(prev.value,-1) != cur.value 
), 
ValuesWithHead as (
    select value 
    , HeadNr = (select max(headnr) 
       from Heads 
       where Heads.rownr <= data.rownr) 
    from OrderedTable data 
) 
select Value, [Count] = count(*) 
from ValuesWithHead 
group by HeadNr, value 
order by count(*) desc 

erhalten Sie folgende Ausgabe:

Value Count 
2  4 
3  3 
1  2 
2  1 
2  1 
7  1 

Use "Top 1" nur die erste Zeile auszuwählen.

Hier ist meine Abfrage, um die Testdaten zu erstellen:

create table YourTable (
    id int primary key, 
    userid int, 
    variable varchar(25), 
    value int 
) 
insert into YourTable (id, userid, variable, value) values (3115, 2287, 'votech05', 2) 
insert into YourTable (id, userid, variable, value) values (3116, 2287, 'comcol05', 1) 
insert into YourTable (id, userid, variable, value) values (3117, 2287, 'fouryr05', 1) 
insert into YourTable (id, userid, variable, value) values (3118, 2287, 'none05', 2) 
insert into YourTable (id, userid, variable, value) values (3119, 2287, 'ocol1_05', 2) 
insert into YourTable (id, userid, variable, value) values (3120, 2287, 'disnone', 2) 
insert into YourTable (id, userid, variable, value) values (3121, 2287, 'dissense', 2) 
insert into YourTable (id, userid, variable, value) values (3122, 2287, 'dismobil', 3) 
insert into YourTable (id, userid, variable, value) values (3123, 2287, 'dislearn', 3) 
insert into YourTable (id, userid, variable, value) values (3124, 2287, 'disment', 3) 
insert into YourTable (id, userid, variable, value) values (3125, 2287, 'disother', 2) 
insert into YourTable (id, userid, variable, value) values (3126, 2287, 'disrefus', 7) 
+0

Nicht genau, da ich die Gesamtzählung jedes Wertes nicht möchte, wie sie gruppiert sind, dh 2,1,2,2,1,1,2,2,2,2,1,1 würde zurückkehren Wert = 2, zählen = 4, nicht 7. –

+0

+1, funktioniert nach dem Bearbeiten, und viel besser als mit einem Cursor! –

+0

Das sieht vielversprechend aus. Lassen Sie mich einen Blick darauf werfen. Ich würde lieber keinen Cursor verwenden, wenn ich ihm helfen kann (obwohl bei diesen Arten von voneinander abhängigen Problemen die Leistung mit einem CTE möglicherweise gleich ausfallen würde). Vielen Dank. –

2

Dies ist eines der Probleme mit Cursor gelöst besten sein kann. Probieren Sie es aus. Es sollte nah sein, aber es wurde nicht getestet, da Sie CREATE TABLE- und INSERT-Anweisungen nicht mit Beispieldaten zur Verfügung gestellt haben, um dies zu vereinfachen.

declare @userid int 
set @userid = 2287; 
declare C cursor fast_forward for 
select VALUE from T 
where USERID = @userid 
order by ID; 

declare @value int, @prevvalue int; 
declare @runcount int, @runlongest int; 
set @runlongest = 0; 
declare @valuelongest int; 
open C; 
fetch next from C into @value; 
while @@fetch_status = 0 begin 
    if @value = @prevvalue set @runcount = @runcount + 1 else set @runcount = 1; 
    if @runcount > @runlongest begin 
    set @runlongest = @runcount; 
    set @valuelongest = @value; 
    end; 
    set @prevvalue = @value; 
    fetch next from C into @value; 
end; 
select @userid as USERID, @valuelongest as VALUE, @runlongest as [COUNT]; 

close C; 
deallocate C; 

Es wird nicht schnell mit 75M Zeilen, aber es wird wahrscheinlich auch nicht zu langsam sein. Wenn Ihre Läufe sehr lang sind und Sie über die richtigen Indizes verfügen, können Sie die Zeilen mit row_number in einer temporären Tabelle nummerieren und dann eine WHILE-Schleife verwenden, die jeweils durch einen Durchlauf springt. Lassen Sie es mich wissen, wenn Sie meinen, dass es sich lohnt, sie zu betrachten (und wenn Sie können, CREATE TABLE- und INSERT-Anweisungen mit Beispieldaten zu posten).

0

ohne es zu testen denke ich, dass die folgenden funktionieren soll:

ROW_NUMBER() über (Partition von Benutzer-ID, Wert, um von id)

einmal dies diejenige auswählen, erfolgt nur mit der höchsten row_nunber

Bitte lassen Sie mich wissen, ob das funktioniert hat !!

Danke, Edi

+0

Edi, row_number() wird nicht funktionieren, da es fortlaufende Werte auf die gleiche Weise behandelt wie nicht aufeinanderfolgende. Die Reihenfolge der Werte ist hier das Thema, nicht nur wie viele es gibt. –

+0

so bedeutet das, dass keine Reihenfolge definiert werden kann? Tut mir leid, ich verstehe das nicht. –