多年来,我一直在对所有类型的聚合查询使用GROUP BY。最近,我一直在逆向工程一些使用PARTITION BY来执行聚合的代码。
在阅读我能找到的所有关于PARTITION BY的文档时,它听起来很像GROUP BY,可能还添加了一些额外的功能。
它们是相同功能的两个版本还是完全不同的东西?
多年来,我一直在对所有类型的聚合查询使用GROUP BY。最近,我一直在逆向工程一些使用PARTITION BY来执行聚合的代码。
在阅读我能找到的所有关于PARTITION BY的文档时,它听起来很像GROUP BY,可能还添加了一些额外的功能。
它们是相同功能的两个版本还是完全不同的东西?
当前回答
它提供汇总数据而不进行汇总
例如,假设我想返回销售区域的相对位置
使用PARTITION BY,我可以返回给定区域的销售额和同一行中所有销售区域的最大销售额。
这确实意味着您将有重复的数据,但它可能适合最终消费者,因为数据已经聚合,但没有数据丢失——就像GROUP BY的情况一样。
其他回答
据我所知,Partition By与Group By几乎相同,但有以下区别:
这个group by实际上对结果集进行分组,每个组返回一行,因此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。
使用GROUP BY时,生成的行通常比输入的行少。
但是,当使用PARTITION BY时,得到的行数应该与传入的行数相同。
小的观察。使用“partition by”动态生成SQL的自动化机制相对于“group by”要简单得多。对于“group by”,我们必须注意“select”列的内容。
对不起,我的英语不好。
-- 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
分区并不会实际卷起数据。它允许您在每个组的基础上重置一些东西。例如,通过对分组字段进行分区并对组中的行使用rownum(),可以获得组中的序数列。这使您的行为有点像在每个组的开头重置的标识列。