2013-05-13 8 views
5

Nie wiem, jak sformułować to pytanie, ale chcę, aby zapytanie zbiorcze było stosowane do wielu wierszy. Mam nadzieję, że przykład ten powinien ułatwić to. Zakładając, że mam następujące dane:Połączone zapytanie zagregowane i niepołączone w SQL

player | year | games 
------------------------- 
ausmubr01 | 2006 | 139 
ausmubr01 | 2007 | 117 
bondsba01 | 2006 | 130 
bondsba01 | 2007 | 126 
stairma01 | 2006 | 26 
stairma01 | 2006 | 77 
stairma01 | 2006 | 14 
stairma01 | 2007 | 125 

A dla każdego gracza w każdym roku, chcę obliczyć ich „letniej karierze”, czyli liczba lat zostały one rozgrywane:

player | year | games | cyear 
-------------------------------- 
ausmubr01 | 2006 | 139 | 1 
ausmubr01 | 2007 | 117 | 2 
bondsba01 | 2006 | 130 | 1 
bondsba01 | 2007 | 126 | 2 
stairma01 | 2006 | 26 | 1 
stairma01 | 2006 | 77 | 2 
stairma01 | 2006 | 14 | 3 
stairma01 | 2007 | 125 | 4 

byłoby naturalne, aby wyrazić tę transformację jako SELECT player, year, games, year - min(year) + 1 as cyear FROM baseball GROUP by player ale z powodu przepisów dotyczących zagregowanych zapytań wyrażenie jest obliczane tylko raz dla każdej grupy:

player | year | games | cyear 
-------------------------------- 
ausmubr01 | 2006 | 139 | 1 
bondsba01 | 2006 | 130 | 1 
stairma01 | 2006 | 26 | 1 

jak mogę przezwyciężyć problem ogólnie (tj. nie tylko w tym przypadku, ale zawsze, gdy chcę wykonać operację arytmetyczną, łączącą istniejącą kolumnę i pojedynczy numer na grupę obliczoną za pomocą funkcji agregującej)?

+1

Proszę podać RDBMS, które są kierowane przez dodanie odpowiedniego znacznika (Oracle, SQL Server, MySQL, itd.) być może odpowiedzi, które wykorzystują języka lub produktu funkcje, które nie są powszechnie obsługiwane. Ponadto, oznaczając je konkretnym RDBMS, twoje pytanie może zostać zwrócone przez osoby lepiej dostosowane do tego, aby na nie odpowiedzieć – Taryn

+1

@blue stóp Jestem zainteresowany odpowiedziami, które odnoszą się szeroko, nie do konkretnego RDBMS. – hadley

Odpowiedz

4

Można użyć ROW_NUMBER dla kariery roku:

SELECT player, year, games, 
     cyear = ROW_NUMBER() OVER (PARTITION BY player ORDER BY year), 
     gamesPerMax = 1.0 * games/MAX(games) OVER (PARTITION BY player) 
FROM dbo.TableName 

Demo

Wystarczy popatrzeć na potężnej OVER clause.

+0

Dzięki - to pomaga w tym konkretnym przypadku, ale nie w ogóle (np. 'Gry/max (gry)' – hadley

+0

@hadley: Potem użyj 'games/MAX (gry) PÓŹNIEJ ...', zredagowałem moją odpowiedź –

+0

To jest przydatne - nie jest obsługiwany przez RDMS, którego używam do prototypowania (sqlite), ale widzę, że obsługuje on także postgresql.) – hadley

0

Wystarczy użyć wielu grup przez ... i suma na żądanym zakresie

GROUP BY player, year 
3

Jedna prosta metoda do obliczania okresu rozpoczynającego się każdego gracza jako zapytania kruszywa oraz dołączyć dane z oryginałem. Tego rodzaju „sekwencji oparte” kwerendy są zwykle trudne do wyrażenia w języku opartego zestaw :(

WITH tmp as (
    select player, min(year) as minyear 
    from table 
    group by player 
); 

select t.*, t.year - t.minyear + 1 as cyear 
from table as t, tmp 
where t.player = tmp.player; 
1

Jeśli nie masz z lub OVER, następnie ... dostać prawdziwą bazę danych. przypadku jego braku, można to zrobić z podzapytania.

SELECT t.*, t.year - subtable.minyear + 1 AS cyear 
FROM table AS t 
JOIN (
    select player, min(year) as minyear 
    from table 
    group by player 
) AS SubTable 
ON T.player = SubTable.player