SQL Server: différence entre PARTITION BY et GROUP BY

366

J'ai utilisé GROUP BYpour tous les types de requêtes agrégées au fil des ans. Récemment, j'ai procédé à la rétro-ingénierie d'un code utilisé PARTITION BYpour effectuer des agrégations. En lisant toute la documentation que je peux trouver PARTITION BY, cela ressemble beaucoup à GROUP BY, peut-être avec un peu de fonctionnalités supplémentaires ajoutées? S'agit-il de deux versions de la même fonctionnalité générale ou s'agit-il de quelque chose de complètement différent?

Mike Mooney
la source

Réponses:

441

Ils sont utilisés à différents endroits. group bymodifie la requête entière, comme:

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

Mais partition byfonctionne juste sur une fonction de fenêtre , comme row_number:

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

A group byréduit normalement le nombre de lignes renvoyées en les enroulant et en calculant des moyennes ou des sommes pour chaque ligne. partition byn'affecte pas le nombre de lignes renvoyées, mais il change la façon dont le résultat d'une fonction de fenêtre est calculé.

Andomar
la source
23
belle réponse, pourriez-vous s'il vous plaît écrire un échantillon d'un résultat renvoyé pour chacun d'eux?
Ashkan Mobayen Khiabani
2
@AshkanMobayenKhiabani, vous pouvez exécuter les deux requêtes contre Northwind, qui peuvent ou non être installées par défaut en fonction de la version de votre serveur SQL. Sinon, vous pouvez le rechercher sur la page des téléchargements.
Fetchez la vache
15
@AshkanMobayenKhiabani La réponse d'Arunprasanth ci-dessous montre des résultats renvoyés qui peuvent vous faire gagner du temps au lieu de sauter à travers plus de cerceaux d'apprentissage et de temps pour apprendre Northwind
Praxiteles
1
Plus d'informations sur les fonctions Windows (en SQL): blog.jooq.org/2013/11/03/…
datps
itcodehub.blogspot.com/2019/03/… - plus d'informations et d'exemple sur les différences entre group by et partition by in sql
xproph
252

Nous pouvons prendre un exemple simple.

Prenons un tableau nommé TableAavec les valeurs suivantes:

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 clause SQL GROUP BY peut être utilisée dans une instruction SELECT pour collecter des données sur plusieurs enregistrements et regrouper les résultats par une ou plusieurs colonnes.

En termes plus simples, l'instruction GROUP BY est utilisée conjointement avec les fonctions d'agrégation pour regrouper l'ensemble de résultats par une ou plusieurs colonnes.

Syntaxe:

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

Nous pouvons appliquer GROUP BYdans notre tableau:

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

Résultats:

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

Dans notre vrai tableau, nous avons 7 lignes et lorsque nous appliquons GROUP BY id, le serveur regroupe les résultats en fonction de id:

En termes simples:

ici GROUP BYréduit normalement le nombre de lignes renvoyées en les enroulant et en calculant Sum()pour chaque ligne.

PARTITION BY

Avant de passer à PARTITION BY, regardons la OVERclause:

Selon la définition MSDN:

La clause OVER définit une fenêtre ou un ensemble de lignes spécifié par l'utilisateur dans un ensemble de résultats de requête. Une fonction de fenêtre calcule ensuite une valeur pour chaque ligne de la fenêtre. Vous pouvez utiliser la clause OVER avec des fonctions pour calculer des valeurs agrégées telles que des moyennes mobiles, des agrégats cumulatifs, des totaux cumulés ou un N supérieur par groupe de résultats.

PARTITION BY ne réduira pas le nombre de lignes renvoyées.

Nous pouvons appliquer PARTITION BY dans notre exemple de tableau:

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

Résultat:

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

Regardez les résultats - il partitionne les lignes et renvoie toutes les lignes, contrairement à GROUP BY.

Arunprasanth KV
la source
3
partition by peut affecter le nombre de lignes, cela ne réduira pas le nombre de lignes.
John
1
Quelle serait la différence si je devais SELECTpasser SELECT DISTINCTà la deuxième requête? cela ne retournerait-il pas le même ensemble de données que la GROUP BYrequête? Quelles sont les raisons de choisir l'un ou l'autre?
Erick 3E
3
@ Erick3E s'il vous plaît jeter un oeil sur cette question stackoverflow.com/questions/20375074/…
Arunprasanth KV
J'aime mieux cette réponse car elle montre comment les fonctions d'agrégation Min / Max / Sum etc. fonctionnent sur les partitions. L'exemple Row_Number () ne le rend pas aussi clair. Normalement, j'utilise une fonction d'agrégation avec GROUP BY, mais je viens de remarquer que PARTITION-OVER a les mêmes méthodes et se demande la même chose que l'OP - ce qui m'a conduit ici. Merci!
ripvlan
53

partition byne fait pas réellement remonter les données. Il vous permet de réinitialiser quelque chose par groupe. Par exemple, vous pouvez obtenir une colonne ordinale au sein d'un groupe en partitionnant le champ de regroupement et en utilisant rownum()les lignes de ce groupe. Cela vous donne quelque chose qui se comporte un peu comme une colonne d'identité qui se réinitialise au début de chaque groupe.

ConcernedOfTunbridgeWells
la source
43

PARTITION BY Divise l'ensemble de résultats en partitions. La fonction de fenêtre est appliquée à chaque partition séparément et le calcul redémarre pour chaque partition.

Trouvé sur ce lien: Clause OVER

Will Marcouiller
la source
36

Il fournit des données cumulées sans remonter

c'est-à-dire supposons que je veuille retourner la position relative de la région de vente

En utilisant PARTITION BY, je peux retourner le montant des ventes pour une région donnée et le montant MAX dans toutes les régions de vente de la même ligne.

Cela signifie que vous aurez des données répétitives, mais cela peut convenir au consommateur final dans le sens où les données ont été agrégées mais aucune donnée n'a été perdue - comme ce serait le cas avec GROUP BY.

ail adolf
la source
3
La meilleure réponse, la plus simple.
tmthyjames
27

PARTITION BYest analytique, tandis que GROUP BYest agrégé. Pour l'utiliser PARTITION BY, vous devez le contenir avec une clause OVER .

Poneys OMG
la source
1
PARTITION BY is analyticcette simple déclaration m'a beaucoup éclairé. +1.
C'est en fait la réponse la plus simple et la meilleure.
jdmneon
22

D'après ce que je comprends, la partition par est presque identique au groupe par, mais avec les différences suivantes:

Ce groupe regroupe en fait le jeu de résultats renvoyant une ligne par groupe, ce qui entraîne donc que SQL Server n'autorise dans la liste SELECT que les fonctions d'agrégation ou les colonnes qui font partie de la clause group by (auquel cas SQL Server peut garantir qu'il existe des fonctions uniques). résultats pour chaque groupe).

Considérez par exemple MySQL qui permet d'avoir dans la liste SELECT des colonnes qui ne sont pas définies dans la clause Group By, auquel cas une ligne est toujours renvoyée par groupe, mais si la colonne n'a pas de résultats uniques, il n'y a aucune garantie quelle sera la sortie!

Mais avec Partition By, bien que les résultats de la fonction soient identiques aux résultats d'une fonction d'agrégation avec Group By, vous obtenez toujours le jeu de résultats normal, ce qui signifie que l'on obtient une ligne par ligne sous-jacente et non une ligne par groupe, et à cause de cela, il peut y avoir des colonnes qui ne sont pas uniques par groupe dans la liste SELECT.

Donc, en résumé, Group By serait mieux quand a besoin d'une sortie d'une ligne par groupe, et Partition By serait mieux quand on a besoin de toutes les lignes mais veut toujours la fonction d'agrégation basée sur un groupe.

Bien sûr, il peut également y avoir des problèmes de performances, voir http://social.msdn.microsoft.com/Forums/ms-MY/transactsql/thread/0b20c2b5-1607-40bc-b7a7-0c60a2a55fba .

yoel halb
la source
2

Lorsque vous utilisez GROUP BY, les lignes résultantes seront généralement inférieures aux lignes entrantes.

Mais, lorsque vous utilisez PARTITION BY, le nombre de lignes résultant doit être le même que celui entrant.

Mahdi Ben Selimene
la source
0

Supposons que nous ayons 14 enregistrements de namecolonne dans le tableau

dans group by

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

il donnera le décompte sur une seule ligne soit 14

mais en partition by

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

il y aura 14 rangées d'augmentation du nombre

Ambrish Rajput
la source
0

Petite observation. Le mécanisme d'automatisation pour générer dynamiquement du SQL en utilisant la «partition par» est beaucoup plus simple à implémenter par rapport au «group by». Dans le cas de «regrouper par», nous devons nous occuper du contenu de la colonne «sélectionner».

Désolé pour mon anglais.

user1785960
la source
0

Il a des scénarios d'utilisation vraiment différents. Lorsque vous utilisez GROUP BY, vous fusionnez certains des enregistrements pour les colonnes identiques et vous disposez d'une agrégation de l'ensemble de résultats.

Cependant, lorsque vous utilisez PARTITION BY, votre jeu de résultats est le même, mais vous disposez simplement d'une agrégation sur les fonctions de la fenêtre et vous ne fusionnez pas les enregistrements, vous aurez toujours le même nombre d'enregistrements.

Voici un article utile sur le rallye expliquant la différence: http://alevryustemov.com/sql/sql-partition-by/

Alev Ryustemov
la source
-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
la source