SQL Server: Unterschied zwischen PARTITION BY und GROUP BY

366

Ich habe im GROUP BYLaufe der Jahre für alle Arten von aggregierten Abfragen verwendet. Vor kurzem habe ich einen Code rückentwickelt PARTITION BY, mit dem Aggregationen durchgeführt werden. Wenn ich die gesamte Dokumentation durchlese, über die ich etwas finden kann PARTITION BY, hört es sich sehr nach etwas an GROUP BY, vielleicht mit ein wenig zusätzlicher Funktionalität? Sind es zwei Versionen derselben allgemeinen Funktionalität oder sind sie etwas völlig anderes?

Mike Mooney
quelle

Antworten:

441

Sie werden an verschiedenen Orten eingesetzt. group byÄndert die gesamte Abfrage wie:

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

Funktioniert aber partition bynur mit einer Fensterfunktion wie row_number:

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

A group byreduziert normalerweise die Anzahl der zurückgegebenen Zeilen, indem sie aufgerollt und Durchschnittswerte oder Summen für jede Zeile berechnet werden. partition byDies hat keinen Einfluss auf die Anzahl der zurückgegebenen Zeilen, ändert jedoch die Berechnung des Ergebnisses einer Fensterfunktion.

Andomar
quelle
23
nette Antwort, würden Sie bitte eine Probe der zurückgegebenen Ergebnisse für jedes von ihnen schreiben?
Ashkan Mobayen Khiabani
2
@AshkanMobayenKhiabani Sie können beide Abfragen für Northwind ausführen, die je nach SQL Server-Version standardmäßig installiert sein können oder nicht. Wenn nicht, können Sie auf der Downloadseite danach suchen.
Fetchez la Vache
15
@AshkanMobayenKhiabani Arunprasanths Antwort unten zeigt zurückgegebene Ergebnisse, die Ihnen Zeit sparen können, anstatt durch mehr Lernrahmen und Zeit zum Lernen von Nordwind zu springen
Praxiteles
1
Mehr zu Windows-Funktionen (in SQL): blog.jooq.org/2013/11/03/…
datps
itcodehub.blogspot.com/2019/03/… - Weitere Informationen und Beispiele zu Unterschieden zwischen Gruppieren nach und Partitionieren in SQL
xproph
252

Wir können ein einfaches Beispiel nehmen.

Stellen Sie sich eine Tabelle TableAmit den folgenden Werten vor:

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

Die SQL GROUP BY-Klausel kann in einer SELECT-Anweisung verwendet werden, um Daten über mehrere Datensätze hinweg zu sammeln und die Ergebnisse nach einer oder mehreren Spalten zu gruppieren.

In einfacheren Worten wird die Anweisung GROUP BY in Verbindung mit den Aggregatfunktionen verwendet, um die Ergebnismenge nach einer oder mehreren Spalten zu gruppieren.

Syntax:

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

Wir können uns GROUP BYin unserer Tabelle bewerben :

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

Ergebnisse:

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

In unserer realen Tabelle haben wir 7 Zeilen und wenn wir uns bewerben GROUP BY id, gruppiert der Server die Ergebnisse basierend auf id:

In einfachen Worten:

Hier wird GROUP BYnormalerweise die Anzahl der zurückgegebenen Zeilen reduziert, indem sie aufgerollt und Sum()für jede Zeile berechnet werden.

PARTITION BY

Bevor wir zu PARTITION BY gehen, schauen wir uns die OVERKlausel an:

Gemäß der MSDN-Definition:

Die OVER-Klausel definiert ein Fenster oder eine benutzerdefinierte Reihe von Zeilen innerhalb einer Abfrageergebnismenge. Eine Fensterfunktion berechnet dann einen Wert für jede Zeile im Fenster. Sie können die OVER-Klausel mit Funktionen verwenden, um aggregierte Werte wie gleitende Durchschnitte, kumulative Aggregate, laufende Summen oder ein Top-N pro Gruppenergebnis zu berechnen.

PARTITION BY reduziert nicht die Anzahl der zurückgegebenen Zeilen.

Wir können PARTITION BY in unserer Beispieltabelle anwenden:

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

Ergebnis:

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

Schauen Sie sich die Ergebnisse an - im Gegensatz zu GROUP BY werden die Zeilen partitioniert und alle Zeilen zurückgegeben.

Arunprasanth KV
quelle
3
partition by kann die Anzahl der Zeilen beeinflussen, reduziert jedoch nicht die Anzahl der Zeilen.
John
1
Was wäre der Unterschied, wenn ich die SELECTin SELECT DISTINCTdie zweite Abfrage ändern würde ? würde das nicht den gleichen Datensatz wie die GROUP BYAbfrage zurückgeben? Was sind die Gründe für die Wahl des einen oder anderen?
Erick 3E
3
@ Erick3E bitte werfen Sie einen Blick auf diese Frage stackoverflow.com/questions/20375074/…
Arunprasanth KV
Diese Antwort gefällt mir besser, weil sie zeigt, wie die Aggregatfunktionen Min / Max / Sum usw. auf Partitionen funktionieren. Das Beispiel Row_Number () macht es nicht so deutlich. Normalerweise verwende ich eine Aggregatfunktion mit GROUP BY, habe aber gerade bemerkt, dass PARTITION-OVER die gleichen Methoden hat und habe mich gefragt, was das OP getan hat - was mich hierher geführt hat. Vielen Dank!
Ripvlan
53

partition byrollt die Daten nicht wirklich auf. Sie können damit etwas pro Gruppe zurücksetzen. Sie können beispielsweise eine Ordnungsspalte innerhalb einer Gruppe abrufen, indem Sie das Gruppierungsfeld partitionieren und rownum()über die Zeilen innerhalb dieser Gruppe verwenden. Dies gibt Ihnen etwas, das sich ein bisschen wie eine Identitätsspalte verhält, die am Anfang jeder Gruppe zurückgesetzt wird.

ConcernedOfTunbridgeWells
quelle
43

PARTITION BY Teilt die Ergebnismenge in Partitionen. Die Fensterfunktion wird auf jede Partition separat angewendet und die Berechnung für jede Partition neu gestartet.

Gefunden unter diesem Link: OVER-Klausel

Will Marcouiller
quelle
36

Es bietet aufgerollte Daten ohne Aufrollen

Angenommen, ich möchte die relative Position der Vertriebsregion zurückgeben

Mit PARTITION BY kann ich den Verkaufsbetrag für eine bestimmte Region und den MAX-Betrag für alle Verkaufsregionen in derselben Zeile zurückgeben.

Dies bedeutet, dass Sie sich wiederholende Daten haben, dies kann jedoch für den Endverbraucher in dem Sinne geeignet sein, dass Daten aggregiert wurden, aber keine Daten verloren gegangen sind - wie dies bei GROUP BY der Fall wäre.

Adolf Knoblauch
quelle
3
Die beste und einfachste Antwort.
tmthyjames
27

PARTITION BYist analytisch, während GROUP BYes aggregiert ist. Um es verwenden zu können PARTITION BY, müssen Sie es mit einer OVER-Klausel enthalten .

OMG Ponys
quelle
1
PARTITION BY is analyticDiese einfache Aussage hat mir viel klar gemacht. +1.
Dies ist eigentlich die einfachste und beste Antwort.
jdmneon
22

Nach meinem Verständnis ist Partition By fast identisch mit Group By, jedoch mit folgenden Unterschieden:

Diese Gruppe gruppiert tatsächlich die Ergebnismenge, die eine Zeile pro Gruppe zurückgibt. Dies führt dazu, dass SQL Server in der SELECT-Liste nur Aggregatfunktionen oder Spalten zulässt, die Teil der group by-Klausel sind (in diesem Fall kann SQL Server garantieren, dass eindeutige Funktionen vorhanden sind Ergebnisse für jede Gruppe).

Stellen Sie sich zum Beispiel MySQL vor, das es erlaubt, in der SELECT-Liste Spalten zu haben, die nicht in der Group By-Klausel definiert sind. In diesem Fall wird immer noch eine Zeile pro Gruppe zurückgegeben. Wenn die Spalte jedoch keine eindeutigen Ergebnisse enthält, gibt es keine Garantie Was wird die Ausgabe sein!

Obwohl mit Partition By die Ergebnisse der Funktion mit den Ergebnissen einer Aggregatfunktion mit Group By identisch sind, erhalten Sie dennoch die normale Ergebnismenge, dh, Sie erhalten eine Zeile pro zugrunde liegender Zeile und nicht eine Zeile pro Zeile Gruppe, und aus diesem Grund kann man Spalten haben, die nicht pro Gruppe in der SELECT-Liste eindeutig sind.

Zusammenfassend ist Group By am besten geeignet, wenn eine Zeile pro Gruppe ausgegeben werden soll, und Partition By ist am besten geeignet, wenn alle Zeilen benötigt werden, die Aggregatfunktion jedoch weiterhin auf einer Gruppe basiert.

Natürlich kann es auch zu Leistungsproblemen kommen, siehe http://social.msdn.microsoft.com/Forums/ms-MY/transactsql/thread/0b20c2b5-1607-40bc-b7a7-0c60a2a55fba .

yoel halb
quelle
2

Wenn Sie verwenden GROUP BY, sind die resultierenden Zeilen normalerweise kleiner als eingehende Zeilen.

Wenn Sie jedoch verwenden PARTITION BY, sollte die resultierende Zeilenanzahl mit der Anzahl der eingehenden Zeilen übereinstimmen.

Mahdi Ben Selimene
quelle
0

Angenommen, wir haben 14 Datensätze der nameSpalte in der Tabelle

im group by

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

es wird in einer Reihe gezählt, dh 14

aber in partition by

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

Es werden 14 Zeilen mehr gezählt

Ambrish Rajput
quelle
0

Kleine Beobachtung. Automatisierungsmechanismus zum dynamischen Generieren von SQL mithilfe der 'Partition von' ist in Bezug auf die 'Gruppieren von' viel einfacher zu implementieren. Im Fall von 'Gruppieren nach' müssen wir uns um den Inhalt der Spalte 'Auswählen' kümmern.

Entschuldigung für mein Englisch.

user1785960
quelle
0

Es gibt wirklich verschiedene Nutzungsszenarien. Wenn Sie GROUP BY verwenden, führen Sie einige der Datensätze für dieselben Spalten zusammen und Sie haben eine Aggregation der Ergebnismenge.

Wenn Sie jedoch PARTITION BY verwenden, ist Ihre Ergebnismenge dieselbe, aber Sie haben nur eine Aggregation über die Fensterfunktionen und Sie führen die Datensätze nicht zusammen, Sie haben immer noch die gleiche Anzahl von Datensätzen.

Hier ist ein hilfreicher Artikel zur Rallye, der den Unterschied erklärt: http://alevryustemov.com/sql/sql-partition-by/

Alev Ryustemov
quelle
-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
quelle