SQL Server: diferencia entre PARTITION BY y GROUP BY

366

He estado usando GROUP BYpara todo tipo de consultas agregadas a lo largo de los años. Recientemente, he realizado ingeniería inversa de un código que se usa PARTITION BYpara realizar agregaciones. Al leer toda la documentación que puedo encontrar PARTITION BY, parece mucho GROUP BY, ¿quizás con un poco de funcionalidad adicional agregada? ¿Son dos versiones de la misma funcionalidad general, o son algo completamente diferente?

Mike Mooney
fuente

Respuestas:

441

Se usan en diferentes lugares. group bymodifica toda la consulta, como:

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

Pero partition bysolo funciona en una función de ventana , como row_number:

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

A group bynormalmente reduce el número de filas devueltas al enrollarlas y calcular promedios o sumas para cada fila. partition byno afecta el número de filas devueltas, pero cambia cómo se calcula el resultado de una función de ventana.

Andomar
fuente
23
buena respuesta, ¿podría escribir una muestra de los resultados devueltos para cada uno de ellos?
Ashkan Mobayen Khiabani
2
@AshkanMobayenKhiabani puede ejecutar ambas consultas contra Northwind, que puede o no instalarse de manera predeterminada según la versión de su servidor SQL. Si no, puede buscarlo en la página de descargas de s.
Fetchez la vache
15
La respuesta a continuación de @AshkanMobayenKhiabani Arunprasanth muestra resultados devueltos que pueden ahorrarle tiempo en lugar de saltar a través de más aros de aprendizaje y tiempo para aprender Northwind
Praxiteles
1
Más sobre las funciones de Windows (en SQL): blog.jooq.org/2013/11/03/…
datps
itcodehub.blogspot.com/2019/03/… - más información y ejemplo sobre las diferencias entre agrupar por y particionar por en sql
xproph
252

Podemos tomar un ejemplo simple.

Considere una tabla TableAcon los siguientes valores:

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 cláusula SQL GROUP BY se puede usar en una instrucción SELECT para recopilar datos en varios registros y agrupar los resultados en una o más columnas.

En palabras más simples, la instrucción GROUP BY se usa junto con las funciones agregadas para agrupar el conjunto de resultados por una o más columnas.

Sintaxis:

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

Podemos aplicar GROUP BYen nuestra tabla:

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

Resultados:

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

En nuestra tabla real tenemos 7 filas y cuando aplicamos GROUP BY id, el servidor agrupa los resultados en función de id:

En palabras simples:

aquí GROUP BYnormalmente reduce el número de filas devueltas al enrollarlas y calcular Sum()para cada fila.

PARTITION BY

Antes de ir a PARTITION BY, veamos la OVERcláusula:

Según la definición de MSDN:

La cláusula OVER define una ventana o un conjunto de filas especificado por el usuario dentro de un conjunto de resultados de consulta. Una función de ventana luego calcula un valor para cada fila en la ventana. Puede usar la cláusula OVER con funciones para calcular valores agregados como promedios móviles, agregados acumulativos, totales acumulados o una N superior por resultados de grupo.

PARTITION BY no reducirá el número de filas devueltas.

Podemos aplicar PARTITION BY en nuestra tabla de ejemplo:

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

Resultado:

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

Mire los resultados: dividirá las filas y devolverá todas las filas, a diferencia de GROUP BY.

Arunprasanth KV
fuente
3
partition by puede afectar el número de filas, simplemente no reducirá el número de filas.
Juan
1
¿Cuál sería la diferencia si yo fuera a cambiar la SELECTen SELECT DISTINCTla segunda consulta? ¿No devolvería eso el mismo conjunto de datos que la GROUP BYconsulta? ¿Cuáles son las razones para elegir uno u otro?
Erick 3E
3
@ Erick3E, eche un vistazo a esta pregunta stackoverflow.com/questions/20375074/…
Arunprasanth KV
Me gusta más esta respuesta porque muestra cómo funcionan las funciones de Agregado Mín / Máx / Suma, etc. en Particiones. El ejemplo Row_Number () no lo deja tan claro. Normalmente uso una función agregada con GROUP BY, pero acabo de notar que PARTITION-OVER tiene los mismos métodos y me pregunté lo mismo que hizo el OP, lo que me llevó aquí. ¡Gracias!
ripvlan 01 de
53

partition byen realidad no acumula los datos. Le permite restablecer algo por grupo. Por ejemplo, puede obtener una columna ordinal dentro de un grupo particionando en el campo de agrupación y utilizando rownum()las filas dentro de ese grupo. Esto le da algo que se comporta un poco como una columna de identidad que se restablece al comienzo de cada grupo.

Preocupado por TunbridgeWells
fuente
43

PARTICIÓN POR Divide el conjunto de resultados en particiones. La función de ventana se aplica a cada partición por separado y el cálculo se reinicia para cada partición.

Encontrado en este enlace: cláusula OVER

Will Marcouiller
fuente
36

Proporciona datos acumulados sin acumular

es decir, supongamos que quiero devolver la posición relativa de la región de ventas

Con PARTITION BY, puedo devolver el importe de ventas para una región determinada y el importe MAX en todas las regiones de ventas en la misma fila.

Esto significa que tendrá datos repetidos, pero puede ser adecuado para el consumidor final en el sentido de que los datos se han agregado pero no se han perdido datos, como sería el caso con GROUP BY.

adolf ajo
fuente
3
La mejor respuesta, la más simple.
tmthyjames
27

PARTITION BYes analítico, mientras que GROUP BYes agregado. Para usarlo PARTITION BY, debe contenerlo con una cláusula OVER .

Ponis OMG
fuente
1
PARTITION BY is analyticEsta simple declaración me aclaró mucho. +1.
Esta es en realidad la respuesta más simple y mejor.
jdmneon el
22

A mi entender, Partition By es casi idéntico a Group By, pero con las siguientes diferencias:

Ese grupo agrupa realmente el conjunto de resultados que devuelve una fila por grupo, lo que da como resultado que SQL Server solo permita en la lista SELECT agregar funciones o columnas que sean parte del grupo por cláusula (en cuyo caso SQL Server puede garantizar que haya un único resultados para cada grupo).

Considere, por ejemplo, MySQL que permite tener en la lista SELECT columnas que no están definidas en la cláusula Group By, en cuyo caso todavía se devuelve una fila por grupo, sin embargo, si la columna no tiene resultados únicos, entonces no hay garantía ¿Cuál será la salida?

Pero con Partition By, aunque los resultados de la función son idénticos a los resultados de una función agregada con Group By, aún se obtiene el conjunto de resultados normal, lo que significa que se obtiene una fila por fila subyacente, y no una fila por grupo, y debido a esto puede tener columnas que no son únicas por grupo en la lista SELECCIONAR.

Como resumen, Group By sería mejor cuando necesita una salida de una fila por grupo, y Partition By sería mejor cuando uno necesita todas las filas pero aún quiere la función de agregado basada en un grupo.

Por supuesto, también puede haber problemas de rendimiento, consulte http://social.msdn.microsoft.com/Forums/ms-MY/transactsql/thread/0b20c2b5-1607-40bc-b7a7-0c60a2a55fba .

yoel halb
fuente
2

Cuando lo use GROUP BY, las filas resultantes serán generalmente menos que las filas entrantes.

Pero, cuando lo usa PARTITION BY, el recuento de filas resultante debe ser el mismo que el entrante.

Mahdi Ben Selimene
fuente
0

Supongamos que tenemos 14 registros de namecolumna en la tabla

en group by

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

dará cuenta en una sola fila, es decir, 14

pero en partition by

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

tendrá 14 filas de aumento en el recuento

Rajput ambrish
fuente
0

Pequeña observación. El mecanismo de automatización para generar SQL de forma dinámica utilizando la 'partición por' es mucho más simple de implementar en relación con el 'agrupar por'. En el caso de 'agrupar por', debemos cuidar el contenido de la columna 'seleccionar'.

Lo siento por mi ingles.

usuario1785960
fuente
0

Tiene escenarios de uso realmente diferentes. Cuando usa GROUP BY, combina algunos de los registros para las columnas que son iguales y tiene una agregación del conjunto de resultados.

Sin embargo, cuando usa PARTICIÓN POR, su conjunto de resultados es el mismo pero solo tiene una agregación sobre las funciones de la ventana y no combina los registros, todavía tendrá el mismo recuento de registros.

Aquí hay un artículo útil que explica la diferencia: http://alevryustemov.com/sql/sql-partition-by/

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