Klausa SQL OVER () - kapan dan mengapa itu berguna?

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

Saya membaca tentang klausa itu dan saya tidak mengerti mengapa saya membutuhkannya. Apa fungsinya Over? Apa yang Partitioning Byharus dilakukan Mengapa saya tidak dapat membuat kueri dengan menulis Group By SalesOrderID?

DenganFlyingColors
sumber
30
Apa pun RDBMS yang Anda gunakan, tutorial Postgres mungkin bisa membantu. Memiliki contoh; membantuku.
Andrew Lazarus

Jawaban:

144

Anda bisa menggunakannya GROUP BY SalesOrderID. Perbedaannya adalah, dengan GROUP BY Anda hanya dapat memiliki nilai gabungan untuk kolom yang tidak termasuk dalam GROUP BY.

Sebaliknya, menggunakan fungsi agregat berjendela alih-alih GROUP BY, Anda dapat mengambil nilai agregat dan non-agregat. Yaitu, meskipun Anda tidak melakukan itu dalam contoh permintaan Anda, Anda bisa mengambil OrderQtynilai individual dan jumlah, jumlah, rata-rata dll. Di atas grup yang sama SalesOrderID.

Berikut adalah contoh praktis mengapa agregat berjendela sangat bagus. Misalkan Anda perlu menghitung berapa persen dari total setiap nilai. Tanpa agregat berjendela Anda harus terlebih dahulu mendapatkan daftar nilai agregat dan kemudian bergabung kembali ke rowset asli, yaitu seperti ini:

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]

Sekarang lihat bagaimana Anda dapat melakukan hal yang sama dengan agregat berjendela:

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

Jauh lebih mudah dan bersih, bukan?

Andriy M
sumber
68

The OVERklausa di kuat bahwa Anda dapat memiliki agregat atas rentang yang berbeda ( "windowing"), apakah Anda menggunakan GROUP BYatau tidak

Contoh: dapatkan jumlah per SalesOrderIDdan jumlah semua

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

Dapatkan berbeda COUNT, tidakGROUP 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)
gbn
sumber
47

Jika Anda hanya ingin KELOMPOK OLEH SalesOrderID maka Anda tidak akan dapat memasukkan kolom ProductID dan OrderQty dalam klausa SELECT.

Klausa PARTITION BY BY memungkinkan Anda memecah fungsi agregat Anda. Satu contoh yang jelas dan berguna adalah jika Anda ingin menghasilkan nomor baris untuk baris pesanan pada pesanan:

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

(Sintaks saya mungkin sedikit tidak aktif)

Anda kemudian akan mendapatkan kembali sesuatu seperti:

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
Tom H
sumber
42

Izinkan saya menjelaskan dengan sebuah contoh dan Anda akan dapat melihat cara kerjanya.

Dengan asumsi Anda memiliki tabel DIM_EQUIPMENT berikut:

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

Jalankan di bawah SQL

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

Hasilnya akan seperti di bawah ini

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

Lihat apa yang terjadi.

Anda dapat menghitung tanpa Group By pada YEAR dan Match dengan ROW.

CARA lain yang menarik untuk mendapatkan hasil yang sama jika seperti di bawah ini menggunakan DENGAN Klausa, DENGAN berfungsi sebagai in-line LIHAT dan dapat menyederhanakan kueri terutama yang kompleks, yang tidak terjadi di sini meskipun karena saya hanya mencoba untuk menunjukkan penggunaan

 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;
Sanjay Singh
sumber
17

Klausa OVER ketika dikombinasikan dengan PARTITION BY menyatakan bahwa pemanggilan fungsi sebelumnya harus dilakukan secara analitis dengan mengevaluasi baris yang dikembalikan dari kueri. Anggap saja sebagai pernyataan GROUP BY inline.

OVER (PARTITION BY SalesOrderID) menyatakan bahwa untuk fungsi SUM, AVG, dll ..., kembalikan nilai OVER subset rekaman yang dikembalikan dari kueri, dan PARTISI yang subset OLEH kunci asing SalesOrderID.

Jadi kami akan SUM setiap record OrderQty untuk SETIAP SalesOrderID UNIK, dan nama kolom itu akan disebut 'Total'.

Ini adalah cara yang JAUH lebih efisien daripada menggunakan banyak tampilan inline untuk mengetahui informasi yang sama. Anda dapat menempatkan kueri ini dalam tampilan inline dan memfilter Total lalu.

SELECT ...,
FROM (your query) inlineview
WHERE Total < 200
maple_shaft
sumber
2
  • Juga Disebut Query PetitionKlausul.
  • Mirip dengan Group ByKlausa

    • memecah data menjadi potongan-potongan (atau partisi)
    • dipisahkan oleh batas partisi
    • melakukan dalam partisi
    • diinisialisasi ulang ketika melintasi batas perpisahan

Sintaks:
function (...) LEBIH DARI (PARTISI DENGAN col1 col3, ...)

  • Fungsi

    • Fungsi akrab seperti COUNT(), SUM(), MIN(), MAX(), dll
    • Fungsi Baru juga (mis ROW_NUMBER(). RATION_TO_REOIRT(), Dll.)


Info lebih lanjut dengan contoh: http://msdn.microsoft.com/en-us/library/ms189461.aspx

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

Itu adalah hasil dari query. Tabel yang digunakan sebagai sumber adalah kecuali sama dengan tidak memiliki kolom terakhir. Kolom ini adalah jumlah bergerak dari yang ketiga.

Pertanyaan:

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

(tabel berlaku untuk publik.iuk)

sql version:  2012

Ini sedikit melebihi level dbase (1986), saya tidak tahu mengapa 25+ tahun diperlukan untuk menyelesaikannya.

Алексей Неудачин
sumber