SQL Server:PARTITION BY和GROUP BY之间的区别


365

这些年来,我一直在使用GROUP BY所有类型的聚合查询。最近,我一直在对一些PARTITION BY用于执行聚合的代码进行逆向工程。在阅读我能找到的所有文档时PARTITION BY,听起来很像GROUP BY,也许其中添加了一些额外的功能?它们是相同功能的两个版本,还是完全不同?

Answers:


440

它们在不同的地方使用。 group by修改整个查询,例如:

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

但是partition by只适用于窗口函数,例如row_number

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

group by通常会降低通过轧制起来,并计算每个行平均或求和返回的行的数目。 partition by不会影响返回的行数,但是会更改窗口函数结果的计算方式。


23
很好的答案,请为每个结果写一个返回结果的样本吗?
Ashkan Mobayen Khiabani

2
@AshkanMobayenKhiabani,您可以针对Northwind运行两个查询,默认情况下可能会或可能不会安装这两个查询,具体取决于您的sql server版本。如果不是,您可以在s下载页面上搜索它。
Fetchez la vache 2014年

15
@AshkanMobayenKhiabani Arunprasanth在下面的回答中显示了返回的结果,可以节省您的时间,而不必花很多时间来学习更多的知识和时间来学习罗斯文
Praxiteles

1
有关Windows函数的更多信息(SQL版本):blog.jooq.org/2013/11/03/…– datps
2016年

itcodehub.blogspot.com/2019/03/…-有关SQL中group by和partition by之间差异的更多信息和示例
xproph

252

我们可以举一个简单的例子。

考虑一个TableA用以下值命名的表:

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

可以在SELECT语句中使用SQL GROUP BY子句来收集多个记录中的数据,并将结果按一个或多个列分组。

简而言之,GROUP BY语句与聚合函数结合使用,以将结果集按一个或多个列分组。

句法:

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

我们可以GROUP BY在表格中申请:

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

结果:

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

在实际表中,我们有7行,当我们应用时GROUP BY id,服务器根据以下结果对结果进行分组id

简单来说:

这里GROUP BY通常通过汇总并Sum()为每一行计算来减少返回的行数。

PARTITION BY

在转到PARTITION BY之前,让我们看一下该OVER子句:

根据MSDN定义:

OVER子句定义查询结果集中的窗口或用户指定的行集。然后,窗口函数将为窗口中的每一行计算一个值。可以将OVER子句与函数一起使用,以计算聚合值,例如移动平均值,累积聚合,运行总计或每组结果的前N个。

PARTITION BY不会减少返回的行数。

我们可以在示例表中应用PARTITION BY:

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

结果:

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

查看结果- 与GROUP BY不同,它将对行进行分区并返回所有行。


3
partition by 影响行数,只会减少行数。
约翰·

1
会有什么区别,如果我是改变SELECTSELECT DISTINCT以第二查询?那会不会返回与GROUP BY查询相同的数据集?选择其中一个的原因是什么?
Erick 3E


我更喜欢这个答案,因为它显示了聚合函数Min / Max / Sum等如何在分区上工作。Row_Number()示例并不清楚。通常,我将聚合函数与GROUP BY一起使用,但是只是注意到PARTITION-OVER具有相同的方法,并且想知道OP所做的相同事情-这导致了我的到来。谢谢!
ripvlan

53

partition by实际上不会汇总数据。它使您可以按组重置某些内容。例如,通过在分组字段上分区并使用rownum()该组中的行,可以在组中获得序数列。这使您的行为有点像在每个组的开头重置的标识列。


43

PARTITION BY将结果集划分为多个分区。窗口函数分别应用于每个分区,并且每个分区的计算重新开始。

在此链接中找到:OVER子句


36

它提供汇总数据而无需汇总

即假设我想返回销售区域的相对位置

使用PARTITION BY,我可以返回给定区域的销售金额以及同一行中所有销售区域的最大金额。

这确实意味着您将拥有重复的数据,但是就数据已聚合但没有数据丢失的意义而言,它可能适合最终用户(与GRO​​UP BY一样)。


3
最好,最简单的答案。
tmthyjames

27

PARTITION BY是分析性的,GROUP BY而是聚合的。为了使用它PARTITION BY,您必须将其包含一个OVER子句


1
PARTITION BY is analytic这个简单的声明为我清除了很多东西。+1。

这实际上是最简单,最好的答案。
jdmneon

22

据我了解,Partition By与Group By几乎相同,但有以下差异:

该group by实际上将结果集分组,每组返回一行,因此导致SQL Server仅允许SELECT列表中的聚合函数或列为group by子句的列(在这种情况下,SQL Server可以保证唯一每组的结果)。

例如,考虑允许在SELECT列表中使用Group By子句中未定义的列的MySQL,在这种情况下,每个组仍返回一行,但是,如果该列没有唯一结果,则无法保证输出是什么!

但是使用Partition By,虽然该函数的结果与使用Group By的聚合函数的结果相同,但您仍将获得正常的结果集,这意味着每个基础行仅获得一行,而不是每个基础行获得一行组,因此在SELECT列表中每个组的列可能不是唯一的。

因此,作为总结,Group By在每个组需要输出一行时是最好的,而Partition By在需要所有行但仍希望基于组的聚合函数时最好。

当然也可能存在性能问题,请参阅http://social.msdn.microsoft.com/Forums/ms-MY/transactsql/thread/0b20c2b5-1607-40bc-b7a7-0c60a2a55fba


2

使用时 GROUP BY,结果行通常少于传入行。

但是,当您使用时PARTITION BY,结果行数应与传入的行数相同。


0

假设我们有14条记录 name在表中列

group by

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

它会在单行中给出计数,即14

但在 partition by

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

它将增加14行


0

小观察。使用“分区依据”动态生成SQL的自动化机制,相对于“分组依据”而言,实现起来要简单得多。对于“分组依据”,我们必须注意“选择”列的内容。

对不起我的英语不好。



-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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.