SQL Server: Diferença entre PARTITION BY e GROUP BY

366

Eu tenho usado GROUP BYpara todos os tipos de consultas agregadas ao longo dos anos. Recentemente, eu tenho feito engenharia reversa de algum código que usa PARTITION BYpara realizar agregações. Ao ler toda a documentação que posso encontrar PARTITION BY, parece muito GROUP BY, talvez com alguma funcionalidade extra adicionada? São duas versões da mesma funcionalidade geral ou são algo completamente diferente?

Mike Mooney
fonte

Respostas:

441

Eles são usados ​​em lugares diferentes. group bymodifica toda a consulta, como:

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

Mas partition byapenas funciona em uma função de janela , como row_number:

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

A group bynormalmente reduz o número de linhas retornadas, acumulando-as e calculando médias ou somas para cada linha. partition bynão afeta o número de linhas retornadas, mas altera como o resultado de uma função da janela é calculado.

Andomar
fonte
23
boa resposta, você poderia escrever uma amostra dos resultados retornados para cada um deles?
Ashkan Mobayen Khiabani 2/11
2
@AshkanMobayenKhiabani, você pode executar as duas consultas no Northwind, que podem ou não ser instaladas por padrão, dependendo da versão do servidor sql. Caso contrário, você pode procurá-lo na página de downloads.
Fetchez la vache
15
A resposta de @AshkanMobayenKhiabani Arunprasanth abaixo mostra retornou resultados que podem poupar tempo ao invés de saltar através de aros mais aprendizagem e tempo para aprender Adamastor
Praxiteles
11
Mais sobre funções do Windows (no SQL): blog.jooq.org/2013/11/03/…
datps 7/16/16
itcodehub.blogspot.com/2019/03/… - mais informações e exemplo sobre diferenças entre agrupar por e partição por em sql
xproph
252

Podemos dar um exemplo simples.

Considere uma tabela nomeada TableAcom os seguintes 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

A cláusula SQL GROUP BY pode ser usada em uma instrução SELECT para coletar dados em vários registros e agrupar os resultados por uma ou mais colunas.

Em palavras mais simples, a instrução GROUP BY é usada em conjunto com as funções agregadas para agrupar o conjunto de resultados por uma ou mais colunas.

Sintaxe:

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

Podemos aplicar GROUP BYem nossa tabela:

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

Resultados:

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

Na nossa tabela real, temos 7 linhas e, quando aplicamos GROUP BY id, o servidor agrupa os resultados com base em id:

Em palavras simples:

aqui GROUP BYnormalmente reduz o número de linhas retornadas, acumulando-as e calculando Sum()para cada linha.

PARTITION BY

Antes de ir para PARTITION BY, vejamos a OVERcláusula:

De acordo com a definição do MSDN:

A cláusula OVER define uma janela ou um conjunto de linhas especificado pelo usuário em um conjunto de resultados da consulta. Uma função de janela calcula um valor para cada linha na janela. Você pode usar a cláusula OVER com funções para calcular valores agregados, como médias móveis, agregados acumulados, totais em execução ou um N superior por resultados de grupo.

PARTITION BY não reduzirá o número de linhas retornadas.

Podemos aplicar PARTITION BY em nossa tabela de exemplos:

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  

Veja os resultados - ele particionará as linhas e retornará todas as linhas, ao contrário de GROUP BY.

Arunprasanth KV
fonte
3
partition by pode afetar o número de linhas, apenas não reduz o número de linhas.
João
11
Qual seria a diferença se eu fosse para mudar o SELECTpara SELECT DISTINCTa segunda consulta? isso não retornaria o mesmo conjunto de dados que a GROUP BYconsulta? Quais são as razões para escolher um ou outro?
Erick 3E
3
@ Erick3E, dê uma olhada nesta questão stackoverflow.com/questions/20375074/…
Arunprasanth KV
Eu gosto mais dessa resposta porque mostra como as funções agregadas Mín / Máx / Soma etc. funcionam em Partições. O exemplo Row_Number () não deixa isso tão claro. Normalmente eu uso uma função agregada com GROUP BY, mas notei que PARTITION-OVER tem os mesmos métodos e imaginava a mesma coisa que o OP - o que me levou até aqui. Obrigado!
ripvlan
53

partition byna verdade, não acumula os dados. Permite redefinir algo em uma base por grupo. Por exemplo, você pode obter uma coluna ordinal dentro de um grupo particionando no campo de agrupamento e usando rownum()sobre as linhas dentro desse grupo. Isso fornece algo que se comporta um pouco como uma coluna de identidade que é redefinida no início de cada grupo.

ConcernedOfTunbridgeWells
fonte
43

PARTITION BY Divide o conjunto de resultados em partições. A função de janela é aplicada a cada partição separadamente e o cálculo é reiniciado para cada partição.

Encontrado neste link: Cláusula OVER

Will Marcouiller
fonte
36

Fornece dados acumulados sem acumular

suponha que eu queira retornar a posição relativa da região de vendas

Usando PARTITION BY, posso devolver o valor das vendas para uma determinada região e o valor MAX em todas as regiões de vendas na mesma linha.

Isso significa que você terá dados repetidos, mas pode atender o consumidor final no sentido de que os dados foram agregados, mas nenhum foi perdido - como seria o caso do GROUP BY.

alho adolf
fonte
3
A melhor e mais simples resposta.
tmthyjames
27

PARTITION BYé analítico, enquanto GROUP BYé agregado. Para usar PARTITION BY, você deve contê-lo com uma cláusula OVER .

Pôneis OMG
fonte
11
PARTITION BY is analyticessa simples declaração esclareceu muito para mim. +1.
Esta é realmente a resposta mais simples e melhor.
Jdmneon 19/11/19
22

Pelo que entendi, a Partição Por é quase idêntica ao Agrupar por, mas com as seguintes diferenças:

Na verdade, esse grupo agrupa o conjunto de resultados retornando uma linha por grupo, o que resulta, portanto, no SQL Server permitindo apenas na lista SELECT funções agregadas ou colunas que fazem parte do grupo por cláusula (nesse caso, o SQL Server pode garantir a existência de caracteres exclusivos). resultados para cada grupo).

Considere, por exemplo, o MySQL, que permite ter na lista SELECT colunas que não estão definidas na cláusula Group By, caso em que uma linha ainda está sendo retornada por grupo, no entanto, se a coluna não tiver resultados exclusivos, não haverá garantia qual será a saída!

Mas com Partition By, embora os resultados da função sejam idênticos aos resultados de uma função agregada com o Group By, você ainda está obtendo o conjunto de resultados normal, o que significa que um está obtendo uma linha por linha subjacente e não uma linha por grupo e, por esse motivo, pode ter colunas que não são exclusivas por grupo na lista SELECT.

Portanto, como um resumo, Agrupar por seria melhor quando precisar de uma saída de uma linha por grupo, e Partição por seria melhor quando alguém precisar de todas as linhas, mas ainda desejar a função agregada com base em um grupo.

É claro que também pode haver problemas de desempenho, consulte http://social.msdn.microsoft.com/Forums/ms-MY/transactsql/thread/0b20c2b5-1607-40bc-b7a7-0c60a2a55fba .

yoel halb
fonte
2

Quando você usa GROUP BY, as linhas resultantes geralmente são menores que as linhas recebidas.

Mas, quando você usa PARTITION BY, a contagem de linhas resultante deve ser igual à entrada.

Mahdi Ben Selimene
fonte
0

Suponha que tenhamos 14 registros de namecoluna na tabela

no group by

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

dará contagem em fila única, ou seja, 14

mas em partition by

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

vai 14 linhas de aumento na contagem

Ambrish Rajput
fonte
0

Pequena observação. Mecanismo de automação para gerar dinamicamente SQL usando a 'partição por', é muito mais simples de implementar em relação ao 'agrupar por'. No caso de 'agrupar por', devemos cuidar do conteúdo da coluna 'selecionar'.

Desculpe pelo meu Inglês.

user1785960
fonte
0

Tem cenários de uso realmente diferentes. Ao usar GROUP BY, você mescla alguns dos registros das colunas iguais e possui uma agregação do conjunto de resultados.

No entanto, quando você usa PARTITION BY, seu conjunto de resultados é o mesmo, mas você só tem uma agregação nas funções da janela e não mescla os registros, ainda terá a mesma contagem de registros.

Aqui está um artigo útil que explica a diferença: http://alevryustemov.com/sql/sql-partition-by/

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