SQL Server: differenza tra PARTITION BY e GROUP BY


366

Ho usato GROUP BYper tutti i tipi di query aggregate nel corso degli anni. Di recente, ho decodificato del codice che utilizza PARTITION BYper eseguire aggregazioni. Nel leggere tutta la documentazione che posso trovare PARTITION BY, sembra molto simile GROUP BY, forse con un po 'di funzionalità aggiuntiva aggiunta? Sono due versioni della stessa funzionalità generale o sono qualcosa di completamente diverso?

Risposte:


441

Sono usati in luoghi diversi. group bymodifica l'intera query, come:

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

Ma partition byfunziona solo su una funzione di finestra , come row_number:

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

A group bynormalmente riduce il numero di righe restituite arrotolandole e calcolando medie o somme per ogni riga. partition bynon influisce sul numero di righe restituite, ma cambia il modo in cui viene calcolato il risultato di una funzione finestra.


23
bella risposta, potresti scrivere un campione dei risultati restituiti per ognuno di essi?
Ashkan Mobayen Khiabani,

2
@AshkanMobayenKhiabani è possibile eseguire entrambe le query su Northwind, che può essere installato o meno in base alla versione del server sql. Altrimenti puoi cercarlo sulla pagina dei download di s.
Fetchez la vache,

15
@AshkanMobayenKhiabani La risposta di Arunprasanth di seguito mostra i risultati restituiti che possono farti risparmiare tempo invece di saltare attraverso più cerchi di apprendimento e tempo per imparare Northwind
Praxiteles

1
Altro sulle funzioni di Windows (in SQL): blog.jooq.org/2013/11/03/…
datps

itcodehub.blogspot.com/2019/03/… - maggiori informazioni ed esempi sulle differenze tra raggruppamento e suddivisione in in sql
xproph

252

Possiamo fare un semplice esempio.

Considera una tabella denominata TableAcon i seguenti valori:

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

La clausola SQL GROUP BY può essere utilizzata in un'istruzione SELECT per raccogliere dati su più record e raggruppare i risultati per una o più colonne.

In parole più semplici, l'istruzione GROUP BY viene utilizzata insieme alle funzioni aggregate per raggruppare il set di risultati per una o più colonne.

Sintassi:

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

Possiamo applicare GROUP BYnella nostra tabella:

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

risultati:

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

Nella nostra tabella reale abbiamo 7 righe e quando applichiamo GROUP BY id, il server raggruppa i risultati in base a id:

In parole semplici:

qui GROUP BYnormalmente si riduce il numero di righe restituite arrotolandole e calcolando Sum()per ogni riga.

PARTITION BY

Prima di andare a PARTITION BY, diamo un'occhiata alla OVERclausola:

Secondo la definizione MSDN:

La clausola OVER definisce una finestra o un set di righe specificato dall'utente all'interno di un set di risultati della query. Una funzione di finestra quindi calcola un valore per ogni riga nella finestra. È possibile utilizzare la clausola OVER con funzioni per calcolare valori aggregati come medie mobili, aggregati cumulativi, totali correnti o risultati di una N superiore per gruppo.

PARTITION BY non ridurrà il numero di righe restituite.

Possiamo applicare PARTITION BY nella nostra tabella di esempio:

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

Risultato:

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

Guarda i risultati: partizionerà le righe e restituirà tutte le righe, a differenza di GROUP BY.


3
partition by può influenzare il numero di righe, semplicemente non riduce il numero di righe.
Giovanni,

1
Quale sarebbe la differenza se dovessi cambiare SELECTin SELECT DISTINCTalla seconda query? non restituirebbe lo stesso set di dati della GROUP BYquery? Quali sono i motivi per scegliere l'uno o l'altro?
Erick 3E

3
@ Erick3E si prega di dare un'occhiata a questo argomento stackoverflow.com/questions/20375074/...
Arunprasanth KV

Mi piace meglio questa risposta perché mostra come funzionano le aggregazioni Min / Max / Sum ecc. Sulle partizioni. L'esempio Row_Number () non lo rende chiaro. Normalmente uso una funzione aggregata con GROUP BY, ma ho appena notato che PARTITION-OVER ha gli stessi metodi e mi chiedevo la stessa cosa che l'OP ha fatto - che mi porta qui. Grazie!
ripvlan

53

partition byin realtà non esegue il rollup dei dati. Ti permette di resettare qualcosa per gruppo. Ad esempio, è possibile ottenere una colonna ordinale all'interno di un gruppo partizionando sul campo di raggruppamento e utilizzando rownum()le righe all'interno di quel gruppo. Questo ti dà qualcosa che si comporta un po 'come una colonna di identità che si reimposta all'inizio di ogni gruppo.


43

PARTITION BY Divide il set di risultati in partizioni. La funzione finestra viene applicata separatamente a ciascuna partizione e il calcolo viene riavviato per ciascuna partizione.

Trovato a questo link: clausola OVER


36

Fornisce i dati di roll-up senza roll-up

cioè supponiamo che io voglia restituire la posizione relativa della regione di vendita

Utilizzando PARTITION BY, posso restituire l'importo delle vendite per una determinata area e l'importo MAX in tutte le aree delle vendite nella stessa riga.

Ciò significa che avrai dati ripetuti, ma potrebbe adattarsi al consumatore finale nel senso che i dati sono stati aggregati ma non sono stati persi, come nel caso di GROUP BY.


3
La risposta migliore e più semplice.
tmthyjames,

27

PARTITION BYè analitico, mentre GROUP BYè aggregato. Per PARTITION BYpoterlo utilizzare , devi contenerlo con una clausola OVER .


1
PARTITION BY is analyticquesta semplice affermazione mi ha chiarito molto. +1.

Questa è in realtà la risposta più semplice e migliore.
jdmneon,

22

Secondo la mia comprensione, Partition By è quasi identico a Group By, ma con le seguenti differenze:

Quel gruppo raggruppa effettivamente il set di risultati che restituisce una riga per gruppo, il che si traduce quindi in SQL Server che consente solo nell'elenco SELECT funzioni o colonne aggregate che fanno parte del gruppo per clausola (nel qual caso SQL Server può garantire che siano univoci risultati per ciascun gruppo).

Si consideri ad esempio MySQL che consente di avere nelle colonne dell'elenco SELECT che non sono definite nella clausola Raggruppa per, nel qual caso viene comunque restituita una riga per gruppo, tuttavia se la colonna non ha risultati univoci, non esiste alcuna garanzia quale sarà l'output!

Ma con Partition By, sebbene i risultati della funzione siano identici ai risultati di una funzione aggregata con Group By, si ottiene comunque il normale set di risultati, il che significa che si ottiene una riga per riga sottostante e non una riga per gruppo e per questo motivo può avere colonne che non sono univoche per gruppo nell'elenco SELEZIONA.

Quindi, come riassunto, Raggruppa per sarebbe meglio quando necessita di un output di una riga per gruppo, e Partizione da sarebbe meglio quando uno ha bisogno di tutte le righe ma vuole comunque la funzione aggregata basata su un gruppo.

Naturalmente potrebbero esserci anche problemi di prestazioni, vedere http://social.msdn.microsoft.com/Forums/ms-MY/transactsql/thread/0b20c2b5-1607-40bc-b7a7-0c60a2a55fba .


2

Quando si utilizza GROUP BY, le righe risultanti saranno in genere inferiori alle righe in arrivo.

Ma, quando lo usi PARTITION BY, il conteggio delle righe risultanti dovrebbe essere uguale a quello in entrata.


0

Supponiamo di avere 14 record di namecolonne nella tabella

in group by

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

darà il conteggio in fila singola, cioè 14

ma in partition by

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

conterà 14 righe di aumento nel conteggio


0

Piccola osservazione. Meccanismo di automazione per generare dinamicamente SQL usando la 'partizione per' è molto più semplice da implementare in relazione al 'raggruppa per'. Nel caso di "raggruppa per", dobbiamo occuparci del contenuto della colonna "seleziona".

Mi scusi per il mio inglese.


0

Ha scenari di utilizzo davvero diversi. Quando si utilizza GROUP BY, si uniscono alcuni dei record per le colonne uguali e si ottiene un'aggregazione del set di risultati.

Tuttavia, quando usi PARTITION BY il tuo set di risultati è lo stesso ma hai solo un'aggregazione sulle funzioni della finestra e non unisci i record, avrai comunque lo stesso numero di record.

Ecco un utile articolo sulla manifestazione che spiega la differenza: http://alevryustemov.com/sql/sql-partition-by/


-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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.