SQL Server: Différence entre PARTITION BY et GROUP BY
-
18-09-2019 - |
Question
Je me sers GROUP BY
pour tous les types de requêtes agrégées au fil des ans. Récemment, j'ai reverse-engineering du code qui utilise PARTITION BY
pour effectuer agrégations. En lisant à travers toute la documentation que je peux trouver à propos PARTITION BY
, il ressemble beaucoup à GROUP BY
, peut-être avec un peu de fonctionnalités supplémentaires ajoutée? Sont-ils deux versions de la même fonctionnalité générale, ou sont-ils tout à fait quelque chose de différent?
La solution
Ils sont utilisés dans des endroits différents. group by
modifie toute la requête, comme:
select customerId, count(*) as orderCount
from Orders
group by customerId
Mais partition by
fonctionne 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 by
réduit normalement le nombre de lignes renvoyées par les enroulant et en calculant des moyennes ou des sommes pour chaque ligne. partition by
ne modifie pas le nombre de lignes retournées, mais il change la façon dont on calcule le résultat d'une fonction de fenêtre.
Autres conseils
Nous pouvons prendre un exemple simple.
Considérons 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
GROUP BY
Le groupe SQL BY clause peut être utilisée dans une instruction SELECT pour recueillir données sur plusieurs disques et regrouper les résultats par un ou plusieurs colonnes.
En termes plus simples GROUP BY est utilisé conjointement avec les fonctions d'agrégation pour regrouper le résultat-ensemble par un 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 BY
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 lorsque nous appliquons GROUP BY id
, le groupe de serveurs les résultats basés sur id
:
En mots simples:
ici
GROUP BY
réduit normalement le nombre de lignes renvoyées en roulant les et calculSum()
pour chaque ligne.
PARTITION BY
Avant d'aller PARTITION BY, nous examinons la clause OVER
:
Selon la définition MSDN:
OVER clause définit un ensemble de lignes ou de fenêtre spécifié par l'utilisateur dans un résultat de la requête. Une fonction de fenêtre calcule alors une valeur pour chaque rangée dans la fenêtre. Vous pouvez utiliser la clause OVER avec des fonctions pour calculer valeurs agrégées telles que les moyennes mobiles, des agrégats cumulatifs, tous les résultats en cours d'exécution, ou une partie supérieure de N par les résultats du groupe.
PARTITION BY ne réduira pas le nombre de lignes retournées.
Nous pouvons appliquer PARTITION BY dans notre tableau exemple:
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 partitionner les lignes et retourne tous lignes, à la différence GROUP BY
. partition by
ne roule pas réellement les données. Il vous permet de réinitialiser quelque chose sur une base par groupe. Par exemple, vous pouvez obtenir une colonne ordinale au sein d'un groupe en partageant sur le champ de regroupement et à l'aide rownum()
sur les lignes de ce groupe. Cela vous donne quelque chose qui se comporte un peu comme une colonne d'identité qui remet à zéro au début de chaque groupe.
PAR PARTITION Divise le jeu de résultats en partitions. La fonction de fenêtre est appliquée à chaque partition séparément et redémarrage de calcul pour chaque partition.
Trouvé à ce lien: SUR l'article
Il fournit des données roulées sans rouler
i.e.. Supposons que je veux retourner la position relative de la région de vente
Utilisation 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 dans la même ligne.
Cela ne signifie que vous aurez à répéter des données, mais il peut convenir au consommateur final, en ce sens que les données ont été agrégées, mais aucune donnée n'a été perdue -. Comme ce serait le cas avec GROUP BY
PARTITION BY
est analytique, alors que GROUP BY
est globale. Pour utiliser PARTITION BY
, vous devez contenir avec un clause OVER .
de ma compréhension partition En est presque identique au groupe par, mais avec les différences suivantes:
Ce groupe par des groupes en fait le jeu de résultats de retour d'une ligne par groupe, ce qui en résulte donc que SQL Server permettant dans les fonctions d'agrégation de la liste SELECT ou des colonnes qui font partie du groupe par la clause (dans ce cas, SQL Server peut garantir que il y a des résultats uniques pour chaque groupe).
Considérons par exemple MySQL qui permet d'avoir dans les colonnes de la liste SELECT qui ne sont pas définis dans le groupe par la clause, auquel cas une ligne est toujours renvoyée par groupe, si la colonne n'a pas des résultats uniques alors il ne garantit ce sera la sortie!
Mais avec la partition par, bien que les résultats de la fonction sont identiques aux résultats d'une fonction d'agrégation avec Grouper par, encore vous obtenez le jeu normal des résultats, ce qui signifie que l'on est d'obtenir une ligne par ligne sous-jacente, et non une ligne par groupe, et à cause de celui-ci peut avoir des colonnes qui ne sont pas uniques par groupe dans la liste SELECT.
En résumé, groupe serait par mieux quand a besoin d'une sortie d'une ligne par groupe et par la partition serait le mieux quand on a besoin de toutes les lignes mais veut toujours la fonction d'agrégation en fonction d'un groupe.
Bien sûr, il pourrait aussi y avoir des problèmes de performance, voir http://social.msdn.microsoft.com/Forums/ms-MY/transactsql/thread/0b20c2b5-1607-40bc-b7a7-0c60a2a55fba .
Supposons que nous ayons 14 dossiers de colonne name
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 i.e. 14
mais dans partition by
select row_number() over (partition by name) as total from person where name = 'Please fill out';
il sera 14 lignes d'augmentation du nombre
observation petite. mécanisme d'automatisation pour générer dynamiquement SQL en utilisant la « partition par » il est beaucoup plus simple à mettre en œuvre en relation avec le « groupe par ». Dans le cas du « groupe par », nous devons prendre soin du contenu de la colonne « select ».
Désolé pour mon anglais.
Il a vraiment différents scénarios d'utilisation. Lorsque vous utilisez GROUP BY vous fusionnez certains des enregistrements pour les colonnes qui sont identiques et vous avez une agrégation de l'ensemble de résultats.
Toutefois, lorsque vous utilisez PARTITION BY votre jeu de résultats est la même, mais vous avez juste 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 rassemblement article expliquant la différence utile: http://alevryustemov.com/sql/sql-partition-by/
-- 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