SQL Server: Różnica między PARTITION BY i GROUP BY

365

Przez lata używałem GROUP BYwszystkich typów zapytań zagregowanych. Ostatnio przerobiłem inżynierię kodu, który używa PARTITION BYdo wykonywania agregacji. Czytając całą dokumentację, którą mogę znaleźć PARTITION BY, brzmi to bardzo podobnie GROUP BY, może z dodaną odrobiną dodatkowej funkcjonalności? Czy są to dwie wersje tej samej ogólnej funkcjonalności, czy też są czymś zupełnie innym?

Mike Mooney
źródło

Odpowiedzi:

440

Są używane w różnych miejscach. group bymodyfikuje całe zapytanie, np .:

select customerId, count(*) as orderCount
from Orders
group by customerId

Ale partition bydziała tylko na funkcję okna , na przykład row_number:

select row_number() over (partition by customerId order by orderId)
    as OrderNumberForThisCustomer
from Orders

group byZazwyczaj zmniejsza liczbę wierszy zwróconych przez walcowanie ich i obliczaniu średnich lub sumy dla każdego rzędu. partition bynie wpływa na liczbę zwracanych wierszy, ale zmienia sposób obliczania wyniku funkcji okna.

Andomar
źródło
23
fajna odpowiedź, czy mógłbyś napisać próbkę zwróconych wyników dla każdego z nich?
Ashkan Mobayen Khiabani
2
@AshkanMobayenKhiabani możesz uruchomić oba zapytania przeciwko Northwind, które mogą, ale nie muszą być instalowane domyślnie w zależności od wersji serwera SQL. Jeśli nie, możesz wyszukać go na stronie pobierania.
Fetchez la vache
15
@AshkanMobayenKhiabani Arunprasanth poniższa odpowiedź pokazuje zwrócone wyniki, które mogą zaoszczędzić czas, zamiast skakać przez kolejne kółka do nauki i czas na naukę Northwind
Praxiteles
1
Więcej informacji o funkcjach systemu Windows (w języku SQL): blog.jooq.org/2013/11/03/…
datps
itcodehub.blogspot.com/2019/03/… - więcej informacji i przykład na temat różnic między grupami i podziałami według w sql
xproph
252

Możemy wziąć prosty przykład.

Rozważ tabelę o TableAnastępujących wartościach:

id  firstname                   lastname                    Mark
-------------------------------------------------------------------
1   arun                        prasanth                    40
2   ann                         antony                      45
3   sruthy                      abc                         41
6   new                         abc                         47
1   arun                        prasanth                    45
1   arun                        prasanth                    49
2   ann                         antony                      49

GROUP BY

Klauzula SQL GROUP BY może być używana w instrukcji SELECT do gromadzenia danych w wielu rekordach i grupowania wyników według jednej lub więcej kolumn.

Mówiąc prościej, instrukcja GROUP BY jest używana w połączeniu z funkcjami agregującymi do grupowania zestawu wyników według jednej lub więcej kolumn.

Składnia:

SELECT expression1, expression2, ... expression_n, 
       aggregate_function (aggregate_expression)
FROM tables
WHERE conditions
GROUP BY expression1, expression2, ... expression_n;

Możemy złożyć GROUP BYw naszej tabeli:

select SUM(Mark)marksum,firstname from TableA
group by id,firstName

Wyniki:

marksum  firstname
----------------
94      ann                      
134     arun                     
47      new                      
41      sruthy   

W naszej prawdziwej tabeli mamy 7 wierszy, a kiedy stosujemy GROUP BY id, serwer grupuje wyniki na podstawie id:

W prostych słowach:

tutaj GROUP BYzwykle zmniejsza liczbę zwracanych wierszy, zwijając je i obliczając Sum()dla każdego wiersza.

PARTITION BY

Zanim przejdziemy do PARTITION BY, spójrzmy na OVERklauzulę:

Zgodnie z definicją MSDN:

Klauzula OVER definiuje okno lub określony przez użytkownika zestaw wierszy w zestawie wyników zapytania. Funkcja okna oblicza następnie wartość dla każdego wiersza w oknie. Możesz użyć klauzuli OVER z funkcjami do obliczania wartości zagregowanych, takich jak średnie ruchome, skumulowane agregaty, sumy bieżące lub wyniki N na górze grupy.

PARTITION BY nie zmniejszy liczby zwracanych wierszy.

Możemy zastosować PARTITION BY w naszej przykładowej tabeli:

SELECT SUM(Mark) OVER (PARTITION BY id) AS marksum, firstname FROM TableA

Wynik:

marksum firstname 
-------------------
134     arun                     
134     arun                     
134     arun                     
94      ann                      
94      ann                      
41      sruthy                   
47      new  

Spójrz na wyniki - podzieli wiersze i zwróci wszystkie wiersze, w przeciwieństwie do GROUP BY.

Arunprasanth KV
źródło
3
partition by może wpływać na liczbę wierszy, to po prostu nie zmniejszy liczby wierszy.
Jan
1
Jaka byłaby różnica, jeśli miałbym zmienić SELECTna SELECT DISTINCTdrugie zapytanie? czy to nie zwróci tego samego zestawu danych co GROUP BYzapytanie? Jakie są powody wyboru jednego lub drugiego?
Erick 3E,
3
@ Erick3E, proszę spojrzeć na to pytanie stackoverflow.com/questions/20375074/…
Arunprasanth KV 6'17
Bardziej podoba mi się ta odpowiedź, ponieważ pokazuje, jak funkcje agregujące Min / Max / Sum itp. Działają na partycjach. Przykład Row_Number () nie wyjaśnia tego tak wyraźnie. Zwykle używam funkcji agregującej z GROUP BY, ale zauważyłem, że PARTITION-OVER ma te same metody i zastanawiałem się nad tym samym, co OP - co mnie tu zaprowadziło. Dzięki!
ripvlan
53

partition bytak naprawdę nie zwija danych. Pozwala zresetować coś na podstawie grupy. Na przykład można uzyskać kolumnę porządkową w grupie, dzieląc ją na pole grupowania i używając rownum()wierszy w tej grupie. To daje coś, co działa trochę jak kolumna tożsamości, która resetuje się na początku każdej grupy.

ConcernedOfTunbridgeWells
źródło
43

PARTITION BY Dzieli zestaw wyników na partycje. Funkcja okna jest stosowana do każdej partycji osobno, a obliczenia uruchamiane są ponownie dla każdej partycji.

Znajduje się pod tym linkiem: OVER Klauzula

Will Marcouiller
źródło
36

Zapewnia zrolowane dane bez zwijania

tj. Załóżmy, że chcę zwrócić względną pozycję regionu sprzedaży

Za pomocą PARTITION BY mogę zwrócić kwotę sprzedaży dla danego regionu i kwotę MAX we wszystkich regionach sprzedaży w tym samym wierszu.

Oznacza to, że będziesz mieć powtarzające się dane, ale może to odpowiadać konsumentowi końcowemu w tym sensie, że dane zostały zagregowane, ale żadne dane nie zostały utracone - tak jak w przypadku GROUP BY.

czosnek Adolf
źródło
3
Najlepsza, najprostsza odpowiedź.
tmthyjames
27

PARTITION BYjest analityczny, podczas gdy GROUP BYjest agregowany. Aby go użyć PARTITION BY, musisz go zawrzeć z klauzulą ​​OVER .

Kucyki OMG
źródło
1
PARTITION BY is analyticto proste stwierdzenie wiele mi wyjaśniło. +1.
To właściwie najprostsza i najlepsza odpowiedź.
jdmneon
22

Z mojego punktu widzenia Partition By jest prawie identyczny jak Group By, ale z następującymi różnicami:

Ta grupa faktycznie grupuje zestaw wyników zwracając jeden wiersz na grupę, co powoduje, że SQL Server zezwala tylko na liście SELECT agregujące funkcje lub kolumny, które są częścią grupy według klauzuli (w takim przypadku SQL Server może zagwarantować, że są unikalne wyniki dla każdej grupy).

Rozważmy na przykład MySQL, który pozwala mieć kolumny listy SELECT, które nie są zdefiniowane w klauzuli Group By, w którym to przypadku jeden wiersz jest nadal zwracany na grupę, jednak jeśli kolumna nie ma unikalnych wyników, nie ma gwarancji jaki będzie wynik!

Ale dzięki Partition By, chociaż wyniki funkcji są identyczne z wynikami funkcji agregującej z Group By, nadal otrzymujesz normalny zestaw wyników, co oznacza, że ​​otrzymujesz jeden wiersz na leżący poniżej wiersz, a nie jeden wiersz na wiersz grupa, z tego powodu można mieć kolumny, które nie są unikalne dla każdej grupy na liście WYBIERZ.

Podsumowując, Group By byłby najlepszy, gdy potrzebuje wyniku jednego wiersza na grupę, a Partition By byłby najlepszy, gdy trzeba wszystkich wierszy, ale nadal chce funkcji agregującej opartej na grupie.

Oczywiście mogą występować również problemy z wydajnością, patrz http://social.msdn.microsoft.com/Forums/ms-MY/transactsql/thread/0b20c2b5-1607-40bc-b7a7-0c60a2a55fba .

yoel halb
źródło
2

Gdy użyjesz GROUP BY, wynikowe wiersze będą zwykle mniejsze niż wiersze przychodzące.

Ale gdy używasz PARTITION BY, wynikowa liczba wierszy powinna być taka sama jak przychodząca.

Mahdi Ben Selimene
źródło
0

Załóżmy, że mamy 14 rekordów namekolumny w tabeli

w group by

select name,count(*) as totalcount from person where name='Please fill out' group BY name;

da licznik w jednym rzędzie, tj. 14

ale w partition by

select row_number() over (partition by name) as total from person where name = 'Please fill out';

zwiększy się o 14 rzędów

Ambrish Rajput
źródło
0

Mała obserwacja. Mechanizm automatyzacji do dynamicznego generowania SQL za pomocą „podziału według” jest znacznie prostszy do wdrożenia w stosunku do „grupowania według”. W przypadku „grupuj według” musimy zadbać o treść kolumny „wybierz”.

Przepraszam za mój angielski.

użytkownik1785960
źródło
0

Ma naprawdę różne scenariusze użytkowania. Podczas korzystania z GROUP BY scalasz niektóre rekordy dla kolumn, które są takie same i masz agregację zestawu wyników.

Jednak gdy używasz PARTITION BY, twój zestaw wyników jest taki sam, ale po prostu masz agregację funkcji okna i nie scalasz rekordów, nadal będziesz mieć taką samą liczbę rekordów.

Oto pomocny rajdowy artykuł wyjaśniający różnicę: http://alevryustemov.com/sql/sql-partition-by/

Alev Ryustemov
źródło
-1
-- BELOW IS A SAMPLE WHICH OUTLINES THE SIMPLE DIFFERENCES
-- READ IT AND THEN EXECUTE IT
-- THERE ARE THREE ROWS OF EACH COLOR INSERTED INTO THE TABLE
-- CREATE A database called testDB


-- use testDB
USE [TestDB]
GO


-- create Paints table
CREATE TABLE [dbo].[Paints](
    [Color] [varchar](50) NULL,
    [glossLevel] [varchar](50) NULL
) ON [PRIMARY]

GO


-- Populate Table
insert into paints (color, glossLevel)
select 'red', 'eggshell'
union
select 'red', 'glossy'
union
select 'red', 'flat'
union
select 'blue', 'eggshell'
union
select 'blue', 'glossy'
union
select 'blue', 'flat'
union
select 'orange', 'glossy'
union
select 'orange', 'flat'
union
select 'orange', 'eggshell'
union
select 'green', 'eggshell'
union
select 'green', 'glossy'
union
select 'green', 'flat'
union
select 'black', 'eggshell'
union
select 'black', 'glossy'
union
select 'black', 'flat'
union
select 'purple', 'eggshell'
union
select 'purple', 'glossy'
union
select 'purple', 'flat'
union
select 'salmon', 'eggshell'
union
select 'salmon', 'glossy'
union
select 'salmon', 'flat'


/*   COMPARE 'GROUP BY' color to 'OVER (PARTITION BY Color)'  */

-- GROUP BY Color 
-- row quantity defined by group by
-- aggregate (count(*)) defined by group by
select count(*) from paints
group by color

-- OVER (PARTITION BY... Color 
-- row quantity defined by main query
-- aggregate defined by OVER-PARTITION BY
select color
, glossLevel
, count(*) OVER (Partition by color)
from paints

/* COMPARE 'GROUP BY' color, glossLevel to 'OVER (PARTITION BY Color, GlossLevel)'  */

-- GROUP BY Color, GlossLevel
-- row quantity defined by GROUP BY
-- aggregate (count(*)) defined by GROUP BY
select count(*) from paints
group by color, glossLevel



-- Partition by Color, GlossLevel
-- row quantity defined by main query
-- aggregate (count(*)) defined by OVER-PARTITION BY
select color
, glossLevel
, count(*) OVER (Partition by color, glossLevel)
from paints
Peoria Os
źródło