424

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

4

13 回答 13

511

它们用于不同的地方。 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

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

于 2010-03-08T20:43:25.253 回答
306

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

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

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;

我们可以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 不同,它将对行进行分区并返回所有行。

于 2015-06-18T06:06:02.823 回答
58

partition by实际上并没有汇总数据。它允许您按组重置某些内容。例如,您可以通过对分组字段进行分区并使用rownum()该组中的行来获取组中的序号列。这为您提供了一些行为有点像在每个组开始时重置的标识列。

于 2010-03-08T20:41:53.217 回答
45

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

在此链接中找到:OVER 子句

于 2010-03-08T20:44:44.537 回答
39

它提供汇总数据而不汇总

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

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

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

于 2010-03-09T16:02:06.200 回答
36

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

于 2010-03-08T20:44:25.890 回答
25

据我了解,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

于 2012-07-19T15:21:32.323 回答
4

PARTITION BY语义

您的问题专门针对 SQL Server,它目前仅支持PARTITION BY窗口函数中的子句,但正如我在这篇博文中解释的关于in SQL的各种含义的PARTITION BY那样,还有其他的,包括:

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

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

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

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

GROUP BY语义

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每个查询只能按一组表达式分组。
于 2022-03-01T08:11:59.557 回答
3

当您使用GROUP BY时,生成的行通常会少于传入的行。

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

于 2019-10-10T20:29:35.597 回答
1

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

对不起我的英语不好。

于 2016-06-10T07:30:23.813 回答
0

假设我们name在表中有 14 列记录

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 行计数

于 2016-04-13T15:54:54.063 回答
0

它有非常不同的使用场景。当您使用 GROUP BY 时,您合并了相同列的一些记录,并且您拥有结果集的聚合。

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

这是一篇解释差异的集会有用文章:http: //alevryustemov.com/sql/sql-partition-by/

于 2019-07-02T09:03:28.433 回答
-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
于 2015-12-01T14:23:12.017 回答