2015-06-30 29 views
5

Wie der Titel schon sagt, möchte ich die erste und die letzte Zeile eines jeden Satzes von Zeilen mit einem GROUP BYWie erhalten Sie den ersten und den letzten Datensatz pro Gruppe in SQL?

Ich habe diese Tabelle mit den folgenden Daten

id group val start end 
1 10  36 465  89   
2 10  35 55  11   
3 10  34 20  456  
4 20  38 1140  1177  
5 20  22 566  788  
6 20  1235 789  4796  
7 20  7894 741  1067 

was ich gruppiert auswählen müssen erhalten sollte den ersten Wert der Spalte Start- und letzten Wertes der Säulenende mit der Gruppe durch die Gruppenspalte

die resultierende Tabelle sein, wie unten

id group val start end 
    1 10  36 465  89 
    3 10  34 20  456  
    4 20  38 1140  1177 
    7 20  7894 741  1067 

ich habe eine Abfrage, aber mit First_value und LAST_VALUE und over (partition by) es ist Arbeit in sql server 2012 aber hat nicht funktioniert in sql server 2008 Ich brauche eine Abfrage, die in sql server 2008

Dank

+0

Die 'MIN' val für' group = 20' sollte 'sein 22',' id = 5'. –

Antwort

6

ausführen können wie etwa ROW_NUMBER mit:

SQL Fiddle

WITH Cte AS(
    SELECT *, 
     RnAsc = ROW_NUMBER() OVER(PARTITION BY [group] ORDER BY val), 
     RnDesc = ROW_NUMBER() OVER(PARTITION BY [group] ORDER BY val DESC) 
    FROM tbl 
) 
SELECT 
    id, [group], val, start, [end] 
FROM Cte 
WHERE 
    RnAsc = 1 OR RnDesc = 1 
ORDER BY [group], val 
+0

Lösung mit 'ROW_NUMBER' funktioniert effizient, wenn Ihre Tabelle klein ist oder die Anzahl der Elemente pro Gruppe klein ist. Wenn Ihre Tabelle groß ist und die Anzahl der Elemente pro Gruppe groß ist und Sie eine separate Tabelle mit der Liste aller Gruppen-IDs haben, wäre CROSS APPLY mit dem entsprechenden Index effizienter. Zum Beispiel hat Ihre Tabelle 100M Zeilen und es gibt nur 10K Gruppen. 'ROW_NUMBER' müsste alle 100M Zeilen lesen, die Zeilennummer für alle berechnen (in der vorgeschlagenen Lösung höchstwahrscheinlich zweimal) und dann den Großteil der Arbeit verwerfen, während Sie wirklich nur 20K Zeilen lesen müssen. –

3

Dies ist ein Weg -

select t.* 
from tbl t 
join (
     select [group], 
       min(val) as val_1, 
       max(val) as val_2 
     from tbl 
     group by [group] 
     ) v 
    on t.[group] = v.[group] 
    and (t.val = v.val_1 
    or t.val = v.val_2); 

Fiddle: http://sqlfiddle.com/#!3/c682f/1/0

Ein anderer Ansatz:

select id, [group], val, [start], [end] 
from(
select t.*, 
     max(val) over(partition by [group]) as max_grp, 
     min(val) over(partition by [group]) as min_grp 
from tbl t 
) x 
where val in (max_grp,min_grp) 
Verwandte Themen