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

时间:2010-03-08 20:40:46

标签: sql-server tsql aggregate-functions window-functions

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

13 个答案:

答案 0 :(得分:380)

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

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

partition by仅适用于a window function,例如row_number

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

group by通常会通过卷起来计算返回的行数,并计算每行的平均值或总和。 partition by不会影响返回的行数,但会更改窗口函数计算结果的方式。

答案 1 :(得分:207)

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

考虑一个名为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不同。

答案 2 :(得分:49)

partition by实际上并未汇总数据。它允许您基于每个组重置某些内容。例如,您可以通过在分组字段上进行分区并在该组中的行上使用rownum()来获取组内的序数列。这会给你一些行为有点像标识列的东西,它会在每个组的开头重置。

答案 3 :(得分:38)

  

分区   将结果集划分为分区。 window函数分别应用于每个分区,并为每个分区重新开始计算。

在此链接中找到:OVER Clause

答案 4 :(得分:29)

它提供汇总数据而不会滚动

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

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

这确实意味着您将拥有重复数据,但它可能适合最终消费者,因为数据已经聚合但没有数据丢失 - 就像GROUP BY一样。

答案 5 :(得分:24)

PARTITION BY是分析性的,而GROUP BY是汇总的。要使用PARTITION BY,您必须使用OVER clause

来包含它

答案 6 :(得分:20)

据我所知,Partition By几乎与Group By相同,但有以下不同之处:

该组实际上对结果集进行分组,每组返回一行,这导致SQL Server只允许SELECT列表中的聚合函数或属于group by子句的列(在这种情况下,SQL Server可以保证每个小组都有独特的结果。)

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

但是使用Partition By,虽然函数的结果与Group By的聚合函数的结果相同,但仍然得到正常的结果集,这意味着每个底层行得到一行,而不是每组一行,因此可以在SELECT列表中为每个组提供不唯一的列。

因此,作为摘要,当需要每组输出一行时,分组依据是最佳的,当需要所有行但仍希望基于组的聚合函数时,分区依据是最佳的。

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

答案 7 :(得分:1)

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

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

答案 8 :(得分: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行计数

答案 9 :(得分:0)

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

抱歉我的英文。

答案 10 :(得分:0)

它的使用场景确实不同。 当您使用GROUP BY时,您合并了一些相同列的记录,并且您对结果集进行了汇总。

但是,当您使用PARTITION BY时,结果集是相同的,但是您只是对窗口函数进行了汇总,并且不合并记录,因此记录数仍然相同。

这是一篇对拉力赛有帮助的文章,解释了两者之间的区别: http://alevryustemov.com/sql/sql-partition-by/

答案 11 :(得分:0)

分区依据是被动的,分组依据是主动的

当应用group by时,输出行的变化大部分会减少,因此是主动的,而在by by中的划分保持相同,使其变为被动,并且由于与之相比,分区中的输出行的变化没有变化,因此与通过...分组。

答案 12 :(得分:-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