195
    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

4

8 回答 8

167

可以使用GROUP BY SalesOrderID. 不同之处在于,使用 GROUP BY,您只能获得未包含在 GROUP BY 中的列的聚合值。

相反,使用窗口聚合函数而不是 GROUP BY,您可以检索聚合值和非聚合值。也就是说,尽管您在示例查询中没有这样做,但您可以在相同s 的OrderQty组中检索单个值及其总和、计数、平均值等。SalesOrderID

这是一个实际示例,说明了为什么窗口聚合很棒。假设您需要计算每个值占总数的百分比。如果没有窗口聚合,您必须首先导出聚合值列表,然后将其连接回原始行集,即像这样:

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

更容易和更清洁,不是吗?

于 2011-06-02T19:54:56.120 回答
76

OVER子句的强大之处在于您可以在不同的范围内进行聚合(“窗口”),无论您是否使用GROUP BYa

示例:获取每个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的 s,不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)
于 2011-06-02T18:59:51.703 回答
51

如果您只想按 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
于 2011-06-02T19:01:20.903 回答
50

让我用一个例子来解释一下,您将能够看到它是如何工作的。

假设您有下表 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

看看发生了什么。

您可以在 YEAR 上没有 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;
于 2014-05-08T06:37:48.560 回答
19

OVER 子句与 PARTITION BY 结合使用时,表示必须通过评估查询的返回行来分析地完成前面的函数调用。将其视为内联 GROUP BY 语句。

OVER (PARTITION BY SalesOrderID)声明对于 SUM、AVG 等函数,返回值 OVER 查询返回的记录的子集,并通过外键 SalesOrderID 对该子集进行分区。

因此,我们将对每个唯一的 SalesOrderID 的每个 OrderQty 记录求和,并且该列名称将称为“总计”。

这是一种比使用多个内联视图来查找相同信息更有效的方法。您可以将此查询放在内联视图中,然后在 Total 上进行过滤。

SELECT ...,
FROM (your query) inlineview
WHERE Total < 200
于 2011-06-02T19:01:05.927 回答
6

简而言之: Over子句可用于选择非聚合值以及聚合值。

Partition BYORDER BY inside 和ROWS 或 RANGE是 OVER() by 子句的一部分。

partition by 用于对数据进行分区,然后执行这些窗口、聚合函数,如果我们没有 partition by,则将整个结果集视为单个分区。

OVER 子句可以与排名函数(Rank、Row_Number、Dense_Rank..)、聚合函数(如(AVG、Max、Min、SUM...等)和分析函数(如 First_Value、Last_Value 等)一起使用。

让我们看看 OVER 子句的基本语法

OVER (   
       [ <PARTITION BY clause> ]  
       [ <ORDER BY clause> ]   
       [ <ROW or RANGE clause> ]  
      )  

PARTITION BY:用于对数据进行分区并对具有相同数据的组执行操作。

ORDER BY:用于定义Partitions中数据的逻辑顺序。当我们不指定 Partition 时,整个结果集被视为单个分区

:这可用于指定在执行操作时应该在分区中考虑哪些行。

举个例子:

这是我的数据集:

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 部分。在这里,我使用按薪水排序并使用"RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW"。在这种情况下,我们没有使用分区,因此整个数据将被视为一个分区,并且我们按薪水排序。这里重要的是UNBOUNDED PRECEDING 和 CURENT ROW。这意味着当我们计算总和时,每行从起始行到当前行。但是,如果我们看到薪水为 5000 且 name="Pavan" 的行,理想情况下它应该是 17000,而薪水 = 5000 和 name=Mark,它应该是 22000。但是当我们使用RANGE在这种情况下,如果它找到任何相似的元素,那么它将它们视为相同的逻辑组并对它们执行操作并将值分配给该组中的每个项目。这就是为什么我们的薪水 = 5000 具有相同值的原因。引擎上升到salary=5000 和Name=Ron 并计算总和,然后将其分配给所有salary=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

因此,与无界前行和当前之间的行不同的是相同值的项目而不是将它们组合在一起,它计算从起始行到当前行的总和,并且它不会像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

这是因为Over(order by Salary)只是Over(order by Salary RANGE BETWEEN UNBOUNDED PRECEDING 和当前行)的一个捷径, 所以无论我们简单地指定Order by without ROWS 或 RANGE,它都采用RANGE BETWEEN UNBOUNDED PRECEDING 和当前行作为默认。

注意:这仅适用于实际接受 RANGE/ROW 的函数。例如,ROW_NUMBER 和少数其他人不接受 RANGE/ROW,在这种情况下,这不会出现在图片中。

到目前为止,我们看到带有 order by 的 Over 子句采用 Range/ROWS,语法看起来像这样RANGE BETWEEN UNBOUNDED PRECEDING AND 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() 是什么?

这只是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

于 2020-08-20T06:00:23.137 回答
4
  • 也称为Query Petition子句。
  • 类似于Group By条款

    • 将数据分解成块(或分区)
    • 按分区边界分隔
    • 功能在分区内执行
    • 跨越分界线时重新初始化

语法:
function (...) OVER (PARTITION BY col1 col3,...)

  • 功能

    • 熟悉的函数,例如COUNT(), SUM(), MIN(), MAX(), 等
    • 新功能(例如ROW_NUMBER(),RATION_TO_REOIRT()等)


更多信息示例:http: //msdn.microsoft.com/en-us/library/ms189461.aspx

于 2014-10-20T17:39:39.610 回答
-4
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 年以上才能完成它。

于 2016-11-17T12:12:42.573 回答