2013-09-26 11 views
5

Załóżmy, że mam tabelę t wypełniony tak:Jak agregować uporządkowane podzbiory wierszy w SQL?

x y z 
- - - 
A 1 A 
A 4 A 
A 6 B 
A 7 A 
B 1 A 
B 2 A 

Zasadniczo kolumny X i Z są losowe litery i Y liczb losowych.

Chcę agregują rzędy następująco:

x z min(y) max(y) 
- - ------ ------ 
A A 1  4 
A B 6  6 
A A 7  7 
B A 1  2 

Innymi słowy: Biorąc pod uwagę, że wiersze są sortowane przez X, Y i Z, wybierz minimalną i maksymalną y dla każdego kolejnej grupy zx i z.

Zauważ, że to zapytanie nie jest to, czego potrzebujesz:

select x, z, min(y), max(y) 
from t 
group by x, z 

Jak miałoby to skutkować następującym niechcianego wyniku:

x z min(y) max(y) 
- - ------ ------ 
A A 1  7 
A B 6  6 
B A 1  2 

Więc pytanie brzmi: czy istnieje sposób, aby wyrazić to, co Chcę w SQL?

(W przypadku, gdy rozwiązanie zależy od dialektu SQL. Rozwiązanie Oracle będzie korzystne)

+2

myślę 'B A 1 1 'jest niepożądany hałas (zgodnie ze specyfikacją). –

+0

Dobrze, przepraszam! – Rubrick

+0

Możesz to osiągnąć za pomocą [Funkcje analityczne] (http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions004.htm). –

Odpowiedz

2

Oto rozwiązanie, ale nie mam czasu, aby wyjaśnić to krok po kroku:

select x, z, min(y), max(y) 
from (
    select b.* , sum(switch) over (order by rn) as grp_new 
    from(
    select a.* , 
      case when grp = (lag(grp) over (order by rn)) 
      then 0 
      else 1 end as switch 
    from 
     (select x,y,z, 
       dense_rank() over (order by x, z) as grp, 
       row_number() over (order by x, y, z) rn 
     from t 
    )a 
)b 
)c 
group by x, z, grp_new 
order by grp_new 

SQLFIDDLE to test it.

0

spróbować

select x, z, min(y), max(y) 
    from (select x, z, y from t order by x, z)) 
group by x, z 
+0

Powoduje to ten sam niepożądany wynik w poście PO. –

+0

Nie rozumiem, co mówisz – sunysen

1

Nie wspominając o wersji Oracle czy dana wersja obsługuje WITH i ROW_NUMBER() OVER

WITH C as 
(
select t.*, 
     ROW_NUMBER() OVER (order by x,y,z) as rn 
from t 
), C2 as 

(
select t1.*, 
( 
    select count(*) from c where Rn<=t1.Rn 
           and (z<>t1.z or x<>t1.x) 
) as Grp 
from c t1 
) 

select x,z,min(y),max(y) from c2 
group by x,z,grp 
order by min(rn) 

SQLFiddle demo

+0

Funkcje okna (inaczej "analityczne" funkcje) są dostępne od Oracle 8.2 i typowych wyrażeń tabel od 9.1. –