Mệnh đề SQL OVER () - khi nào và tại sao nó hữu ích?


169
    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);

Tôi đọc về điều khoản đó và tôi không hiểu tại sao tôi cần nó. Hàm này Overlàm gì? Không gì Partitioning Bylàm gì? Tại sao tôi không thể thực hiện một truy vấn bằng văn bản Group By SalesOrderID?


30
Bất kể bạn sử dụng RDBMS nào, hướng dẫn Postgres có thể hữu ích. Có ví dụ; đã giúp tôi
Andrew Lazarus

Câu trả lời:


144

Bạn có thể sử dụng GROUP BY SalesOrderID. Sự khác biệt là, với GROUP BY, bạn chỉ có thể có các giá trị tổng hợp cho các cột không được bao gồm trong GROUP BY.

Ngược lại, sử dụng các hàm tổng hợp có cửa sổ thay vì GROUP BY, bạn có thể truy xuất cả các giá trị tổng hợp và không tổng hợp. Đó là, mặc dù bạn không làm điều đó trong truy vấn mẫu của mình, bạn có thể truy xuất cả các OrderQtygiá trị riêng lẻ và tổng, tổng, trung bình, v.v. của chúng trên các nhóm có cùng SalesOrderIDs.

Đây là một ví dụ thực tế về lý do tại sao tổng hợp cửa sổ là tuyệt vời. Giả sử bạn cần tính phần trăm của tổng giá trị là bao nhiêu. Nếu không có các tổng hợp có cửa sổ, trước tiên bạn phải lấy ra một danh sách các giá trị tổng hợp và sau đó nối nó trở lại hàng gốc, tức là như thế này:

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]

Bây giờ hãy xem cách bạn có thể làm tương tự với tổng hợp có cửa sổ:

SELECT
  [Partition],
  Value,
  Value * 100.0 / SUM(Value) OVER (PARTITION BY [Partition]) AS ValuePercent
FROM OriginalRowset orig

Dễ dàng và sạch sẽ hơn nhiều phải không?


68

Các OVERkhoản là mạnh mẽ ở chỗ bạn có thể có uẩn trên phạm vi khác nhau ( "windowing"), cho dù bạn sử dụng mộtGROUP BY hay không

Ví dụ: lấy số lượng trên SalesOrderIDvà số lượng của tất cả

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

Nhận COUNTs khác nhau , khôngGROUP 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)

47

Nếu bạn chỉ muốn NHÓM THEO SalesOrderID thì bạn sẽ không thể bao gồm các cột ProductID và OrderQty trong mệnh đề SELECT.

Mệnh đề PHẦN THAM GIA cho phép bạn chia nhỏ các hàm tổng hợp của mình. Một ví dụ rõ ràng và hữu ích sẽ là nếu bạn muốn tạo số dòng cho các dòng đơn hàng trên một đơn hàng:

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

(Cú pháp của tôi có thể bị tắt một chút)

Sau đó, bạn sẽ nhận lại một cái gì đó như:

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

42

Hãy để tôi giải thích với một ví dụ và bạn sẽ có thể thấy nó hoạt động như thế nào.

Giả sử bạn có bảng sau DIM_EQUIPMENT:

VIN         MAKE    MODEL   YEAR    COLOR
-----------------------------------------
1234ASDF    Ford    Taurus  2008    White
1234JKLM    Chevy   Truck   2005    Green
5678ASDF    Ford    Mustang 2008    Yellow

Chạy bên dưới SQL

SELECT VIN,
  MAKE,
  MODEL,
  YEAR,
  COLOR ,
  COUNT(*) OVER (PARTITION BY YEAR) AS COUNT2
FROM DIM_EQUIPMENT

Kết quả sẽ như dưới đây

VIN         MAKE    MODEL   YEAR    COLOR     COUNT2
 ----------------------------------------------  
1234JKLM    Chevy   Truck   2005    Green     1
5678ASDF    Ford    Mustang 2008    Yellow    2
1234ASDF    Ford    Taurus  2008    White     2

Xem những gì đã xảy ra.

Bạn có thể đếm mà không cần Nhóm theo NĂM và Kết hợp với ROW.

Một CÁCH thú vị khác để có kết quả tương tự nếu như dưới đây bằng cách sử dụng VỚI khoản, VỚI hoạt động như XEM nội tuyến và có thể đơn giản hóa truy vấn đặc biệt phức tạp, điều này không xảy ra ở đây mặc dù tôi chỉ đang cố gắng hiển thị cách sử dụng

 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;

17

Mệnh đề QUÁN khi được kết hợp với PHẦN TÍNH THEO trạng thái rằng lệnh gọi hàm trước phải được thực hiện phân tích bằng cách đánh giá các hàng trả về của truy vấn. Hãy nghĩ về nó như là một tuyên bố NHÓM nội tuyến.

OVER (PARTITION BY SalesOrderID) đang nói rằng đối với hàm SUM, AVG, v.v ..., hãy trả về giá trị QUÁ một tập hợp con của các bản ghi được trả về từ truy vấn và PHẦN THAM GIA mà tập hợp con theo khóa ngoài SalesOrderID.

Vì vậy, chúng tôi sẽ TỪNG mỗi bản ghi OrderQty cho MACHI doanh số bán hàng UNIITE và tên cột đó sẽ được gọi là 'Tổng'.

Đó là một phương tiện hiệu quả hơn nhiều so với việc sử dụng nhiều chế độ xem nội tuyến để tìm ra cùng một thông tin. Bạn có thể đặt truy vấn này trong chế độ xem nội tuyến và bộ lọc trên Total sau đó.

SELECT ...,
FROM (your query) inlineview
WHERE Total < 200

2
  • Cũng gọi là Query Petitionkhoản.
  • Tương tự như Group Bykhoản

    • chia dữ liệu thành các khối (hoặc phân vùng)
    • ngăn cách bởi giới hạn phân vùng
    • chức năng thực hiện trong các phân vùng
    • khởi tạo lại khi vượt qua ranh giới chia tay

Cú pháp:
function (...) QUÁ (THAM GIA B colNG col1 col3, ...)

  • Chức năng

    • Chức năng quen thuộc như COUNT(), SUM(), MIN(), MAX(), vv
    • Chức năng mới cũng như (ví dụ ROW_NUMBER(), RATION_TO_REOIRT()vv)


Thêm thông tin với ví dụ: http://msdn.microsoft.com/en-us/l Library / ms189461.aspx


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

Đó là kết quả của truy vấn. Bảng được sử dụng làm nguồn là cùng một ngoại lệ mà nó không có cột cuối cùng. Cột này là một tổng di chuyển của thứ ba.

Truy vấn:

SELECT prkey,whatsthat,cash,SUM(cash) over (order by whatsthat)
    FROM public.iuk order by whatsthat,prkey
    ;

(bảng đi như công khai.iuk)

sql version:  2012

Đó là một chút so với mức dbase (1986), tôi không biết tại sao cần hơn 25 năm để hoàn thành nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.