USE AdventureWorks2008R2;
GO
SELECT SalesOrderID, ProductID, OrderQty
,SUM(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Total'
,AVG(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Avg'
,COUNT(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Count'
,MIN(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Min'
,MAX(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Max'
FROM Sales.SalesOrderDetail
WHERE SalesOrderID IN(43659,43664);
我读到了这个条款,我不明白为什么需要它。
函数Over
有什么作用? Partitioning By
做了什么?
为什么我不能写Group By SalesOrderID
来查询?
答案 0 :(得分:134)
你可以使用GROUP BY SalesOrderID
。区别在于,对于GROUP BY,您只能拥有GROUP BY中未包含的列的聚合值。
相反,使用窗口聚合函数而不是GROUP BY,您可以检索聚合和非聚合值。也就是说,虽然您在示例查询中没有这样做,但您可以检索单个OrderQty
值以及它们在相同SalesOrderID
s的组中的总和,计数,平均值等。
这是一个实际的例子,说明为什么窗口聚合很好。假设您需要计算每个值的总百分比。如果没有窗口化聚合,您必须首先派生聚合值列表,然后将其连接回原始行集,即如下所示:
SELECT
orig.[Partition],
orig.Value,
orig.Value * 100.0 / agg.TotalValue AS ValuePercent
FROM OriginalRowset orig
INNER JOIN (
SELECT
[Partition],
SUM(Value) AS TotalValue
FROM OriginalRowset
GROUP BY [Partition]
) agg ON orig.[Partition] = agg.[Partition]
现在看一下如何使用窗口化聚合:
SELECT
[Partition],
Value,
Value * 100.0 / SUM(Value) OVER (PARTITION BY [Partition]) AS ValuePercent
FROM OriginalRowset orig
更简单,更清洁,不是吗?
答案 1 :(得分:65)
OVER
子句非常强大,因为无论使用GROUP BY
还是不使用
示例:获取每SalesOrderID
的计数和所有
SELECT
SalesOrderID, ProductID, OrderQty
,COUNT(OrderQty) AS 'Count'
,COUNT(*) OVER () AS 'CountAll'
FROM Sales.SalesOrderDetail
WHERE
SalesOrderID IN(43659,43664)
GROUP BY
SalesOrderID, ProductID, OrderQty
获取不同的COUNT
,无GROUP BY
SELECT
SalesOrderID, ProductID, OrderQty
,COUNT(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'CountQtyPerOrder'
,COUNT(OrderQty) OVER(PARTITION BY ProductID) AS 'CountQtyPerProduct',
,COUNT(*) OVER () AS 'CountAllAgain'
FROM Sales.SalesOrderDetail
WHERE
SalesOrderID IN(43659,43664)
答案 2 :(得分:43)
如果您只想要GROUP BY SalesOrderID,那么您将无法在SELECT子句中包含ProductID和OrderQty列。
PARTITION BY子句让你分解你的聚合函数。一个明显而有用的例子是,如果您想为订单上的订单行生成行号:
SELECT
O.order_id,
O.order_date,
ROW_NUMBER() OVER(PARTITION BY O.order_id) AS line_item_no,
OL.product_id
FROM
Orders O
INNER JOIN Order_Lines OL ON OL.order_id = O.order_id
(我的语法可能略有偏差)
然后你会得到类似的东西:
order_id order_date line_item_no product_id
-------- ---------- ------------ ----------
1 2011-05-02 1 5
1 2011-05-02 2 4
1 2011-05-02 3 7
2 2011-05-12 1 8
2 2011-05-12 2 1
答案 3 :(得分:37)
让我用一个例子来解释,你就能看到它是如何运作的。
假设您有下表DIM_EQUIPMENT:
VIN MAKE MODEL YEAR COLOR
-----------------------------------------
1234ASDF Ford Taurus 2008 White
1234JKLM Chevy Truck 2005 Green
5678ASDF Ford Mustang 2008 Yellow
在SQL下面运行
SELECT VIN,
MAKE,
MODEL,
YEAR,
COLOR ,
COUNT(*) OVER (PARTITION BY YEAR) AS COUNT2
FROM DIM_EQUIPMENT
结果如下
VIN MAKE MODEL YEAR COLOR COUNT2
----------------------------------------------
1234JKLM Chevy Truck 2005 Green 1
5678ASDF Ford Mustang 2008 Yellow 2
1234ASDF Ford Taurus 2008 White 2
看看发生了什么。
你可以在没有Group By的情况下计算年份并与ROW匹配。
另一种有趣的方法如果使用WITH子句得到相同的结果,WITH作为内联VIEW工作,可以简化查询特别复杂的查询,但这不是这里的情况,因为我只是想显示用法
WITH EQ AS
( SELECT YEAR AS YEAR2, COUNT(*) AS COUNT2 FROM DIM_EQUIPMENT GROUP BY YEAR
)
SELECT VIN,
MAKE,
MODEL,
YEAR,
COLOR,
COUNT2
FROM DIM_EQUIPMENT,
EQ
WHERE EQ.YEAR2=DIM_EQUIPMENT.YEAR;
答案 4 :(得分:16)
OVER子句与PARTITION BY结合使用时,必须通过评估返回的查询行来分析地完成前面的函数调用。可以将其视为内联GROUP BY语句。
OVER (PARTITION BY SalesOrderID)
表示对于SUM,AVG等...函数,返回值OVER从查询中返回的记录的子集,以及PARTITION子集BY外键SalesOrderID。
因此,我们将为每个UNIQUE SalesOrderID的每个OrderQty记录进行SUM,并且该列名称将被称为“Total”。
与使用多个内联视图查找相同的信息相比,这是一种更有效的方法。您可以将此查询放在内联视图中,然后按总计过滤。
SELECT ...,
FROM (your query) inlineview
WHERE Total < 200
答案 5 :(得分:2)
Query Petition
条款。与Group By
条款类似
语法:
功能(...)OVER(分类为col1 col3,...)
功能
COUNT()
,SUM()
,MIN()
,MAX()
等ROW_NUMBER()
,RATION_TO_REOIRT()
等)
更多信息,例如:http://msdn.microsoft.com/en-us/library/ms189461.aspx
答案 6 :(得分:0)
所以简单来说: Over 子句可用于选择非聚合值以及聚合值。
内部的分区BY , ORDER BY 和 ROWS或RANGE 是OVER()by子句的一部分。
partition by用于对数据进行分区,然后执行这些窗口,聚合函数,如果没有分区,则将整个结果集视为单个分区。
OVER子句可与排名函数(Rank,Row_Number,Dense_Rank ..),聚合函数(如AVG,Max,Min,SUM等)和Analytics函数(如First_Value,Last_Value等)一起使用。
让我们看看OVER子句的基本语法
OVER (
[ <PARTITION BY clause> ]
[ <ORDER BY clause> ]
[ <ROW or RANGE clause> ]
)
根据: 它用于对数据进行分区并在具有相同数据的组上执行操作。
订购者: 它用于定义分区中数据的逻辑顺序。如果不指定分区,则整个结果集将被视为单个分区
: 可以用来指定执行该操作时应该在分区中考虑哪些行。
让我们举个例子:
这是我的数据集:
Id Name Gender Salary
----------- -------------------------------------------------- ---------- -----------
1 Mark Male 5000
2 John Male 4500
3 Pavan Male 5000
4 Pam Female 5500
5 Sara Female 4000
6 Aradhya Female 3500
7 Tom Male 5500
8 Mary Female 5000
9 Ben Male 6500
10 Jodi Female 7000
11 Tom Male 5500
12 Ron Male 5000
所以让我执行不同的场景,看看数据如何受到影响,我将从困难的语法变成简单的语法
Select *,SUM(salary) Over(order by salary RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as sum_sal from employees
Id Name Gender Salary sum_sal
----------- -------------------------------------------------- ---------- ----------- -----------
6 Aradhya Female 3500 3500
5 Sara Female 4000 7500
2 John Male 4500 12000
3 Pavan Male 5000 32000
1 Mark Male 5000 32000
8 Mary Female 5000 32000
12 Ron Male 5000 32000
11 Tom Male 5500 48500
7 Tom Male 5500 48500
4 Pam Female 5500 48500
9 Ben Male 6500 55000
10 Jodi Female 7000 62000
只需观察sum_sal部分。在这里,我使用的是按薪水排序,并使用“无限制的前导和当前行之间的范围” 。 在这种情况下,我们不使用分区,因此整个数据将被视为一个分区,并且我们按薪水排序。 这里重要的是未绑定的前行和当前行。这意味着当我们计算总和时,从每一行的开始行到当前行。 但是,如果我们看到薪水为5000且名称为“ Pavan”的行,则理想情况下应为17000,薪水为5000且名称为Mark的行应为22000。但是由于我们使用的是 RANGE 在这种情况下,如果找到任何相似的元素,则将它们视为相同的逻辑组并对它们执行操作,并为该组中的每个项目分配值。这就是为什么我们对薪金= 5000具有相同的值的原因。引擎将薪金提高到5000 = Name = Ron并计算总和,然后将其分配给所有薪金= 5000。
Select *,SUM(salary) Over(order by salary ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as sum_sal from employees
Id Name Gender Salary sum_sal
----------- -------------------------------------------------- ---------- ----------- -----------
6 Aradhya Female 3500 3500
5 Sara Female 4000 7500
2 John Male 4500 12000
3 Pavan Male 5000 17000
1 Mark Male 5000 22000
8 Mary Female 5000 27000
12 Ron Male 5000 32000
11 Tom Male 5500 37500
7 Tom Male 5500 43000
4 Pam Female 5500 48500
9 Ben Male 6500 55000
10 Jodi Female 7000 62000
因此,对于无界前导行和当前行之间的行,区别在于相同值的项目而不是将它们分组在一起,它计算从开始行到当前行的SUM,并且不处理相同行的项目值与 RANGE
不同Select *,SUM(salary) Over(order by salary) as sum_sal from employees
Id Name Gender Salary sum_sal
----------- -------------------------------------------------- ---------- ----------- -----------
6 Aradhya Female 3500 3500
5 Sara Female 4000 7500
2 John Male 4500 12000
3 Pavan Male 5000 32000
1 Mark Male 5000 32000
8 Mary Female 5000 32000
12 Ron Male 5000 32000
11 Tom Male 5500 48500
7 Tom Male 5500 48500
4 Pam Female 5500 48500
9 Ben Male 6500 55000
10 Jodi Female 7000 62000
这些结果与
相同Select *, SUM(salary) Over(order by salary RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as sum_sal from employees
这是因为超额(按薪水排序)只是超额(按薪水排序)的无限制限制,当前行之间的距离 因此,无论我们在什么地方简单地指定排序依据而没有 ROWS或RANGE ,它都将未绑定先行和当前行之间的范围作为默认值。
注意:这仅适用于实际接受RANGE / ROW的函数。例如,ROW_NUMBER和其他一些人不接受RANGE / ROW,在这种情况下,这不会出现在图片中。
到目前为止,我们看到带有子句的Over子句采用了Range / ROWS,语法看起来像这样 UNBOUNDED PRECEDING和CURRENT ROW之间的范围 它实际上是从第一行开始计算到当前行。但是,如果要计算整个数据分区的值并为每一列(从第一行到最后一行)使用它,该怎么办。这是该查询
Select *,sum(salary) Over(order by salary ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as sum_sal from employees
Id Name Gender Salary sum_sal
----------- -------------------------------------------------- ---------- ----------- -----------
1 Mark Male 5000 62000
2 John Male 4500 62000
3 Pavan Male 5000 62000
4 Pam Female 5500 62000
5 Sara Female 4000 62000
6 Aradhya Female 3500 62000
7 Tom Male 5500 62000
8 Mary Female 5000 62000
9 Ben Male 6500 62000
10 Jodi Female 7000 62000
11 Tom Male 5500 62000
12 Ron Male 5000 62000
我指定的是 UNBOUNDED FOLLOWING ,而不是CURRENT ROW,它指示引擎计算直到每一行的分区的最后一条记录。
现在您想知道什么是带有空花括号的OVER()?
这只是超额付款的捷径(按无约束的前提和无约束的跟随之间的工资行排序)
此处我们间接指定将所有结果集视为一个分区,然后从每个分区的第一条记录到最后一条记录进行计算。
Select *,Sum(salary) Over() as sum_sal from employees
Id Name Gender Salary sum_sal
----------- -------------------------------------------------- ---------- ----------- -----------
1 Mark Male 5000 62000
2 John Male 4500 62000
3 Pavan Male 5000 62000
4 Pam Female 5500 62000
5 Sara Female 4000 62000
6 Aradhya Female 3500 62000
7 Tom Male 5500 62000
8 Mary Female 5000 62000
9 Ben Male 6500 62000
10 Jodi Female 7000 62000
11 Tom Male 5500 62000
12 Ron Male 5000 62000
我确实为此制作了一个视频,如果您有兴趣可以访问它。 https://www.youtube.com/watch?v=CvVenuVUqto&t=1177s
谢谢, 帕万·库玛(Pavan Kumar Aryasomayajulu) HTTP://xyzcoder.github.io
答案 7 :(得分:-2)
prkey whatsthat cash
890 "abb " 32 32
43 "abbz " 2 34
4 "bttu " 1 35
45 "gasstuff " 2 37
545 "gasz " 5 42
80009 "hoo " 9 51
2321 "ibm " 1 52
998 "krk " 2 54
42 "kx-5010 " 2 56
32 "lto " 4 60
543 "mp " 5 65
465 "multipower " 2 67
455 "O.N. " 1 68
7887 "prem " 7 75
434 "puma " 3 78
23 "retractble " 3 81
242 "Trujillo's stuff " 4 85
这是查询的结果。用作源的表与没有最后一列的表相同。这一列是第三列的移动总和。
查询:
SELECT prkey,whatsthat,cash,SUM(cash) over (order by whatsthat)
FROM public.iuk order by whatsthat,prkey
;
(表格为public.iuk)
sql version: 2012
它有点超过dbase(1986)的水平,我不知道为什么要完成它需要25年以上。