多年来,我一直在对所有类型的聚合查询使用GROUP BY。最近,我一直在逆向工程一些使用PARTITION BY来执行聚合的代码。

在阅读我能找到的所有关于PARTITION BY的文档时,它听起来很像GROUP BY,可能还添加了一些额外的功能。

它们是相同功能的两个版本还是完全不同的东西?


当前回答

使用GROUP BY时,生成的行通常比输入的行少。

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

其他回答

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

在此链接找到:OVER子句

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

分区并不会实际卷起数据。它允许您在每个组的基础上重置一些东西。例如,通过对分组字段进行分区并对组中的行使用rownum(),可以获得组中的序数列。这使您的行为有点像在每个组的开头重置的标识列。

按语义分区

你的问题是关于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只能根据每个查询的一组表达式进行分组。

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