SQL server 2005 – SUM'ing ein Feld, aber nur für das erste Vorkommen eines zweiten Feldes

Plattform: SQL server 2005 Express

Haftungsausschluss: Ich bin ein Anfänger für SQL und so, wenn Sie glücklich sind, mit dem zu helfen, was eine sehr einfache Frage sein kann, dann werde ich nicht beleidigt sein, wenn Sie langsam sprechen und kleine Wörter verwenden 🙂

Ich habe einen Tisch, wo ich den Inhalt mehrerer Zeilen sortieren möchte. Allerdings möchte ich eine Spalte nur für das erste Auftreten von Text in einer anderen Spalte.

Table schema for table 'tblMain' fldOne {varchar(100)} Example contents: “Dandelion“ fldTwo {varchar(8)} Example contents: “01:00:00” (represents hh:mm:ss) fldThree {numeric(10,0)} Example contents: “65” 

Inhalt der Tabelle:

 Zeilennummer fldOne fldTwo fldThree
 ------------------------------------------------
 1 Löwenzahn 01:00:00 99
 2 Gänseblümchen 02:15:00 88
 3 Löwenzahn 00:45:00 77
 4 Löwenzahn 00:30:00 10
 5 Löwenzahn 00:15:00 200
 6 Rose 01:30:00 55
 7 Gänseblümchen 01:00:00 22
 etc. ad nausium

Wenn ich benutze:

 Select * from tblMain where fldTwo < '05:00:00' order by fldOne, fldTwo desc 

Dann werden alle Zeilen korrekt zurückgegeben, von fldOne und dann fdTwo in absteigender Reihenfolge bestellt (obwohl in den Beispieldaten, die ich gezeigt habe, alle data bereits in der richtigen Reihenfolge sind!)

Was ich gerne machen möchte, bekomme die SUM von jedem fldThree , aber nur vom ersten Auftreten jedes fldOne .

Also, Sagen Sie den ersten Löwenzahn, Gänseblümchen und Rose, auf den ich stoße. Z. B. 99 + 88 + 55

Im Moment mache ich das programmatisch; gib ein RecordSet aus der Select-statement oben zurück, und MoveNext durch jede zurückgegebene Zeile, nur fldThree zu meinem 'total' hinzufügen, wenn ich den Text noch nie von fldOne gesehen habe . Es funktioniert, aber die meisten der Select-Abfragen kehren über 100k Zeilen zurück und so ist es ziemlich langsam (langsam ist ein relativer Begriff – es dauert etwa 50 Sekunden auf meinem Setup).

Die eigentliche select-statement (Auswahl von ca. 100k Zeilen aus 1,5m Gesamtzeilen) schließt unter einer Sekunde ab, was gut ist. Die aktuelle Programmschleife ist ziemlich klein und eng, es ist nur die Anzahl der loops durch das RecordSet, das time braucht. Ich benutze adOpenForwardOnly und adLockReadOnly, wenn ich den datasatz öffne.

Dies ist eine Routine, die grundsätzlich kontinuierlich läuft, da mehr data hinzugefügt werden, und auch die fdTwo 'mal' variieren, so kann ich nicht spezifischer mit der Select-statement sein.

Alles, was ich so weit geschafft habe, nativ mit SQL zu funktionieren, scheint schnell zu laufen und ich hoffe, ich kann die Logik (und Arbeit) weg von meinem Programm nehmen und SQL bekommen, um die Belastung zu nehmen.

Danke im Voraus

Der beste path, um dies zu erreichen, ist mit windowsfunktionen. Diese lassen Sie die Zeilen innerhalb einer Gruppe aufzählen. Allerdings brauchst du einen path, um die erste Zeile zu identifizieren. SQL-Tabellen sind inhärent ungeordnet, also benötigen Sie eine Spalte, um die Bestellung anzugeben. Hier sind einige Ideen.

Wenn du eine ID-Spalte hast, die als identity definiert ist, so wird sie autoincrementiert:

 select sum(fldThree) from (select m.*, row_number() over (partition by fldOne order by id) as seqnum from tblMain m ) m where seqnum = 1 

Um eine beliebige Zeile zu bekommen, könntest du:

 select sum(fldThree) from (select m.*, row_number() over (partition by fldOne order by (select NULL as noorder)) as seqnum from tblMain m ) m where seqnum = 1 

Oder wenn FldTwo die Werte in umgekehrter Reihenfolge hat:

 select sum(fldThree) from (select m.*, row_number() over (partition by fldOne order by FldTwo desc) as seqnum from tblMain m ) m where seqnum = 1 

Vielleicht das?

 SELECT SUM(fldThree) as ExpectedSum FROM (SELECT *, ROW_NUMBER() OVER (PARTITION BY fldOne ORDER BY fldTwo DSEC) Rn FROM tblMain) as A WHERE Rn = 1