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

Mik*_*ney 338 t-sql sql-server aggregate-functions window-functions

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

And*_*mar 412

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

select customerId, count(*) as orderCount
from Orders
group by customerId
Run Code Online (Sandbox Code Playgroud)

partition by只适用于窗口函数,如row_number:

select row_number() over (partition by customerId order by orderId)
    as OrderNumberForThisCustomer
from Orders
Run Code Online (Sandbox Code Playgroud)

A group by通常会通过将它们向上滚动并计算每行的平均值或总和来减少返回的行数. partition by不会影响返回的行数,但会改变计算窗口函数结果的方式.

  • 很好的答案,请你为每个人写一份返回结果的样本吗? (20认同)
  • @AshkanMobayenKhiabani Arunprasanth的答案显示了返回的结果,可以节省您的时间,而不是跳过更多的学习篮球和学习Northwind的时间 (14认同)
  • @AshkanMobayenKhiabani您可以对Northwind运行两个查询,默认情况下可能安装也可能不安装,具体取决于您的sql server版本.如果没有,您可以在下载页面上搜索它. (2认同)

Aru*_*K V 229

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

我们有一个以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
Run Code Online (Sandbox Code Playgroud)

通过...分组

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;
Run Code Online (Sandbox Code Playgroud)

我们可以在表格中应用GroupBy

select SUM(Mark)marksum,firstname from TableA
group by id,firstName
Run Code Online (Sandbox Code Playgroud)

结果:

marksum  firstname
----------------
94      ann                      
134     arun                     
47      new                      
41      sruthy   
Run Code Online (Sandbox Code Playgroud)

在我们的实际表中,我们有7行,当我们按ID应用group时,服务器根据id对结果进行分组

简单来说

这里group by通常会减少通过卷起它们并计算每行的Sum来返回的行数.

分区

在去分区之前

让我们看看OVER条款

根据MSDN定义

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

partition by不会减少返回的行数

我们可以在示例表中应用分区

SELECT SUM(Mark) OVER (PARTITION BY id) AS marksum, firstname FROM TableA
Run Code Online (Sandbox Code Playgroud)

结果:

marksum firstname 
-------------------
134     arun                     
134     arun                     
134     arun                     
94      ann                      
94      ann                      
41      sruthy                   
47      new  
Run Code Online (Sandbox Code Playgroud)

看看它会对行进行分区的结果,并导致所有行都不像group by.

  • @ Erick3E请看看这个问题/sf/ask/1426255211/ (3认同)
  • `partition by`*可以*影响行数,它不会*减少*行数. (2认同)

Con*_*lls 51

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


Wil*_*ler 40

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

在此链接中找到:OVER Clause


ado*_*ic 34

它提供汇总数据而不会卷起来

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

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

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

  • 最好,最简单的答案. (3认同)

OMG*_*ies 25

PARTITION BY是分析的,GROUP BY而是聚合的.要使用PARTITION BY,您必须使用OVER子句包含它.

  • “PARTITION BY 是分析性的”这个简单的陈述让我明白了很多。+1。 (6认同)

yoe*_*alb 22

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

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

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

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

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

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


Luk*_*der 9

PARTITION BY语义

\n

您的问题具体是关于 SQL Server 的,它目前仅支持PARTITION BY窗口函数中的子句,但正如我在这篇博客文章中解释的有关SQL 中的各种含义PARTITION BY,还有其他含义,包括:

\n
    \n
  • 窗口分区(窗口函数是 SQL 标准)
  • \n
  • 表分区(用于组织存储的供应商特定扩展,例如在OraclePostgreSQL中)
  • \n
  • MATCH_REGOGNIZE分区(这也是 SQL 标准)
  • \n
  • MODELSPREADSHEET分区(Oracle 对 SQL 的扩展)
  • \n
  • OUTER JOIN分区(SQL 标准)
  • \n
\n

除了最后一个子句重新使用PARTITION BY语法来实现某种CROSS JOIN逻辑之外,所有这些PARTITION BY子句都具有相同的含义:

\n
\n

分区将数据集分成不重叠的子集。

\n
\n

基于此分区,可以实现每个分区的进一步计算或存储操作。例如,对于窗口函数,例如COUNT(*) OVER (PARTITION BY criteria),该COUNT(*)值是按分区计算的。

\n

GROUP BY语义

\n

GROUP BY允许类似的分区行为,尽管它也以各种奇怪的方式转换整个查询的语义。大多数查询GROUP BY可以使用窗口函数重写,尽管通常,GROUP BY语法更简洁,而且可能也更好优化。

\n

例如,这些在逻辑上是相同的,但我希望该GROUP BY子句执行得更好:

\n
-- Classic\nSELECT a, COUNT(*)\nFROM t\nGROUP BY a\n\n-- Using window functions\nSELECT DISTINCT a, COUNT(*) OVER (PARTITION BY a)\nFROM t\n
Run Code Online (Sandbox Code Playgroud)\n

主要区别在于:

\n
    \n
  • 窗口函数也可以是非聚合函数,例如ROW_NUMBER()
  • \n
  • 每个窗口函数可以有自己的PARTITION BY子句,而GROUP BY每个查询只能按一组表达式进行分组。
  • \n
\n