2010-03-08 89 views
233

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

回答

270

它们在不同的地方使用。 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不会影响返回的行数,但它会更改窗口函数结果的计算方式。

+8

很好的答案,请你为他们每个人写一个返回结果的样本吗? – 2013-11-02 21:57:56

+2

@AshkanMobayenKhiabani您可以针对Northwind运行这两个查询,根据您的sql服务器版本,默认情况下可能不会安装这些查询。如果没有,您可以在下载页面上搜索它。 – 2014-01-17 09:14:36

+9

@AshkanMobayenKhiabani Arunprasanth的回答如下显示返回的结果,可以节省您的时间,而不是跳过更多的学习环节和时间学习Northwind – Praxiteles 2016-01-16 10:18:42

42

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

20

PARTITION BY是解析,而GROUP BY是聚合。为了使用PARTITION BY,你必须包含一个OVER clause

+0

'PARTITION BY是analytic'这个简单的语句为我清除了很多。 +1。 – 2017-03-09 15:40:28

33

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

在这个环节发现:OVER Clause

22

它提供卷起的数据,而不卷起

即假设我想返回销售区域

的相对位置使用PARTITION BY,我可以返回给定区域之间的销售金额,即同一行中所有销售地区的最高金额。

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

+0

最好,最简单的答案。 – tmthyjames 2017-05-30 14:48:08

18

至于我的理解分区中的几乎是相同的分组,但是有以下区别:

即通过实际组的结果集返回每个组一行,因此这将导致SQL Server只允许在组SELECT列表聚合函数或属于group by子句一部分的列(在这种情况下,SQL Server可以保证每个组都有唯一的结果)。

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

但是使用Partition By,虽然函数的结果与Group By的集合函数的结果相同,但您仍然得到正常结果集,这意味着每个基础行都获得一行,并且而不是每组一行,并且因为这个可以在SELECT列表中具有每个组都不唯一的列。

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

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

127

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

我们有一个名为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 

集团通过

的SQL GROUP BY子句可以在SELECT语句被用来收集在多个记录和组结果由一个或多个 列 数据。

更简单的说法GROUP BY语句与 一起使用,用于将结果集按一个或多个 列分组。

语法:

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

我们可以在表应用的GroupBy

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

结果:

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

在我们真正的表,我们有7行的时候我们按ID应用组,服务器组根据ID

在简单的话

这里按通常的结果降低了滚动 起来,并计算总和返回的每个行的行数。

分区由

打算通过

分区之前,让我们来看看OVER子句

按照MSDN定义

OVER子句定义一个窗口或用户指定的一组行薄一个 查询结果集。窗口函数然后计算窗口中每行 的值。您可以使用带有函数的OVER子句来计算汇总值,例如移动平均值,累计汇总数,运行总计数 或每组最高结果N。

分区中不会减少的行数返回

我们可以在我们的例子表应用分区

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。

+1

我想你的意思是'select SUM(Mark)OVER(PARTITION BY id)as marksum ...' – mbomb007 2016-04-13 14:59:11

+1

'partition by * * *会影响行数,它不会减少行数。 – John 2017-05-12 11:17:20

+0

@John感谢您的评论,文章编辑 – 2017-05-12 12:30:18

-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 
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

小观察。使用'partition by'动态生成SQL的自动化机制相对于'group by'实现要简单得多。在'group by'的情况下,我们必须关注'select'列的内容。

对不起,我的英语。