多年来,我一直在对所有类型的聚合查询使用GROUP BY。最近,我一直在逆向工程一些使用PARTITION BY来执行聚合的代码。
在阅读我能找到的所有关于PARTITION BY的文档时,它听起来很像GROUP BY,可能还添加了一些额外的功能。
它们是相同功能的两个版本还是完全不同的东西?
多年来,我一直在对所有类型的聚合查询使用GROUP BY。最近,我一直在逆向工程一些使用PARTITION BY来执行聚合的代码。
在阅读我能找到的所有关于PARTITION BY的文档时,它听起来很像GROUP BY,可能还添加了一些额外的功能。
它们是相同功能的两个版本还是完全不同的东西?
当前回答
使用GROUP BY时,生成的行通常比输入的行少。
但是,当使用PARTITION BY时,得到的行数应该与传入的行数相同。
其他回答
分区的 将结果集划分为多个分区。窗口函数分别应用于每个分区,并为每个分区重新启动计算。
在此链接找到:OVER子句
我们可以举一个简单的例子。
考虑一个名为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
集团
可以在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之前,让我们看一下OVER子句:
根据MSDN的定义:
控件中定义窗口或用户指定的行集 查询结果集。然后,窗口函数为每一行计算一个值 在窗户里。可以对函数使用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不同。
它们被用在不同的地方。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不影响返回的行数,但是它 更改窗口函数结果的计算方式。
据我所知,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。
按语义分区
你的问题是关于SQL Server的,它目前只在窗口函数中支持PARTITION BY子句,但正如我在这篇博客文章中解释的那样,在SQL中PARTITION BY还有其他的含义,包括:
窗口分区(窗口函数是SQL标准) 表分区(供应商特定的扩展来组织存储,例如在Oracle或PostgreSQL中) MATCH_REGOGNIZE分区(这也是一个SQL标准) MODEL或SPREADSHEET分区(SQL的Oracle扩展) OUTER JOIN分区(SQL标准)
除了最后一个,它重用了PARTITION BY语法来实现某种交叉连接逻辑,所有这些PARTITION BY子句都有相同的含义:
分区将一个数据集划分为不重叠的子集。
基于此分区,可以对每个分区执行进一步的计算或存储操作。例如,对于窗口函数,如COUNT(*) OVER (PARTITION BY criteria), COUNT(*)值是按每个分区计算的。
按语义分组
GROUP BY允许类似的分区行为,尽管它也以各种奇怪的方式转换整个查询的语义。大多数使用GROUP BY的查询可以使用窗口函数重写,尽管GROUP BY语法通常更简洁,也可能得到更好的优化。
例如,这些在逻辑上是相同的,但我希望GROUP BY子句执行得更好:
-- Classic
SELECT a, COUNT(*)
FROM t
GROUP BY a
-- Using window functions
SELECT DISTINCT a, COUNT(*) OVER (PARTITION BY a)
FROM t
关键的区别在于:
窗口函数也可以是非聚合函数,例如ROW_NUMBER() 每个窗口函数都可以有自己的PARTITION BY子句,而GROUP BY只能根据每个查询的一组表达式进行分组。