2010-03-08 15 views
233

J'ai utilisé GROUP BY pour tous les types de requêtes d'agrégat au fil des ans. Récemment, j'ai fait du reverse-engineering de code qui utilise PARTITION BY pour effectuer des agrégations. En lisant toute la documentation que je peux trouver sur PARTITION BY, cela ressemble beaucoup à GROUP BY, peut-être avec un peu de fonctionnalité supplémentaire ajouté? Sont-ils deux versions de la même fonctionnalité générale, ou sont-ils quelque chose de complètement différent?SQL Server: Différence entre PARTITION BY et GROUP BY

Répondre

270

Ils sont utilisés dans différents endroits. group by modifie toute la requête, comme:

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

Mais partition by fonctionne seulement sur a window function, comme row_number:

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

Un group by réduit normalement le nombre de lignes renvoyées en les roulant et le calcul des moyennes ou des sommes pour chaque rangée. partition by n'affecte pas le nombre de lignes renvoyées, mais modifie la façon dont le résultat d'une fonction de fenêtre est calculé.

+8

bonne réponse, pourriez-vous s'il vous plaît écrire un échantillon d'un résultat retourné pour chacun d'eux? –

+2

@AshkanMobayenKhiabani vous pouvez exécuter les deux requêtes contre Northwind, qui peut ou non être installé par défaut en fonction de la version de votre serveur sql. Sinon, vous pouvez le rechercher sur la page des téléchargements. –

+9

@AshkanMobayenKhiabani La réponse d'Arunprasanth ci-dessous montre des résultats retournés qui peuvent vous faire gagner du temps plutôt que de passer à travers des cerceaux d'apprentissage et du temps pour apprendre Northwind – Praxiteles

42

partition by ne fait pas rouler les données. Cela vous permet de réinitialiser quelque chose par groupe. Par exemple, vous pouvez obtenir une colonne ordinale dans un groupe en partitionnant le champ de regroupement et en utilisant rownum() sur 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.

20

PARTITION BY est analytique, tandis que GROUP BY est agrégé. Afin d'utiliser PARTITION BY, vous devez le contenir avec un OVER clause.

+0

'PARTITION BY est analytique', cette simple déclaration m'a beaucoup éclairé. +1 –

33

PARTITION BY Divise le jeu 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é à ce lien: OVER Clause

22

Il fournit des données roulées sans rouler

-à-dire que je veuille revenir la position relative de la région de vente

Utiliser PARTITION BY, je peut renvoyer le montant des ventes pour une région donnée et le montant MAX pour toutes les régions de vente dans la même rangée. Cela signifie que vous aurez des données répétées, 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.

+0

La meilleure réponse, la plus simple. – tmthyjames

18

À partir de ma partition de compréhension En est presque identique au groupe par, mais avec les différences suivantes:

Ce groupe par des groupes en fait le résultat renvoyant un ensemble d'une ligne par groupe, ce qui entraîne donc dans SQL Server ne permet en la liste SELECT regroupe les fonctions ou les colonnes qui font partie de la clause group by (dans ce cas, SQL Server peut garantir des résultats uniques pour chaque groupe).Considérons 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 retournée par groupe, mais si la colonne n'a pas de résultats uniques, alors 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 pas une rangée par groupe, et à cause de cela, on peut avoir des colonnes qui ne sont pas uniques par groupe dans la liste SELECT. Donc, en résumé, Group By serait mieux quand il faut 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égat 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.

127

Nous pouvons prendre un exemple simple

nous avons une table nommée TableA avec 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 

Groupe par

GROUP SQL BY clause peut être utilisée dans une instruction SELECT pour recueillir des données sur plusieurs enregistrements et regrouper les résultats par un 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 GroupBy dans 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 vraie table, nous avons 7 lignes et quand nous appliquons le groupe par id , Le groupe de serveurs les résultats basés sur id

En mots simples

ici groupe en réduit normalement le nombre de lignes renvoyées en roulant les et le calcul Somme pour chaque ligne.

partition par

avant d'aller à la partition par

regardons clause OVER

Comme par définition MSDN

OVER clause définit une fenêtre ou un ensemble de lignes spécifié par l'utilisateur wi affiner un ensemble de résultats de requête . Une fonction de fenêtre calcule ensuite une valeur pour chaque ligne dans 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 résultat N par groupe supérieur.

partition en ne réduira pas le nombre de lignes retournées

nous pouvons appliquer la partition par dans notre exemple 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 

regard sur le résultats, il va partitionner les lignes et résultats toutes les lignes pas comme le groupe par.

+1

Je pense que vous voulez dire 'sélectionnez SUM (Mark) OVER (PARTITION PAR id) AS marksum ...' – mbomb007

+1

'partition par' * peut * affecter le nombre de lignes, il ne sera pas * réduire * le nombre de lignes. – John

+0

@John merci pour le commentaire, post édité –

-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 
0

Supposons que nous avons 14 dossiers de name colonne dans le tableau

dans group by

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

il donnera le nombre en ligne unique soit 14

mais partition by

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

il sera 14 rangées d'augmentation en nombre

0

Petite observation. Mécanisme d'automatisation pour générer dynamiquement du SQL en utilisant la 'partition par' il est beaucoup plus simple à implémenter par rapport au 'groupe par'. Dans le cas de 'group by', nous devons prendre en charge le contenu de la colonne 'select'.

Désolé pour mon anglais.