SQL OVER () yan tümcesi - ne zaman ve neden yararlıdır?


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

Bu maddeyi okudum ve neden ihtiyacım olduğunu anlamıyorum. İşlev ne yapar Over? Ne yapar Partitioning By? Yazarken neden sorgulama yapamıyorum Group By SalesOrderID?


30
Hangi RDBMS'yi kullanırsanız kullanın, Postgres öğreticisi yardımcı olabilir. Örnekleri vardır; bana yardımcı oldu.
Andrew Lazarus

Yanıtlar:


144

Sen edebilirsiniz kullanmak GROUP BY SalesOrderID. Aradaki fark, GROUP BY ile yalnızca GROUP BY içinde bulunmayan sütunlar için birleştirilmiş değerlere sahip olabilirsiniz.

Bunun aksine, GROUP BY yerine pencereli toplama işlevlerini kullanarak hem toplanmış hem de toplanmamış değerleri alabilirsiniz. Yani, örnek sorgunuzda bunu yapmamanıza rağmen OrderQty, aynı SalesOrderIDs grupları üzerinden hem bireysel değerleri hem de toplamlarını, sayılarını, ortalamalarını vb . Alabilirsiniz.

Pencereli agregaların neden mükemmel olduğuna dair pratik bir örnek. Her bir değerin toplamının yüzde kaçını hesaplamanız gerektiğini varsayalım. Pencereli toplamalar olmadan önce birleştirilmiş değerlerin bir listesini türetmeniz ve daha sonra orijinal satır kümesine geri eklemeniz gerekir, örneğin:

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]

Şimdi aynı şeyi pencereli bir toplama ile nasıl yapabileceğinize bakın:

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

Çok daha kolay ve temiz, değil mi?


68

OVERBir kullanmak ister fıkra, siz ( "pencereleme") farklı aralıklar üzerinde agrega sahip olabileceği güçlü olduğu GROUP BYya da değil

Örnek: başına SalesOrderIDsayım ve hepsinin sayımı

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

Farklı COUNTs al, hayırGROUP 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

Yalnızca SalesOrderID TARAFINDAN GRUP ETMEK istiyorsanız, SELECT yan tümcesinde ProductID ve OrderQty sütunlarını ekleyemezsiniz.

PARTITION BY yan tümcesi, toplama işlevlerinizi parçalamanıza izin verir. Açık ve kullanışlı bir örnek, bir siparişteki sipariş satırları için satır numaraları oluşturmak istiyorsanız:

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

(Sözdizim biraz kapalı olabilir)

Sonra şöyle bir şey geri alırsınız:

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

Bir örnekle açıklayayım ve bunun nasıl çalıştığını görebilirsiniz.

Aşağıdaki tabloya sahip olduğunuzu varsayarsak DIM_EQUIPMENT:

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

SQL altında çalıştır

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

Sonuç aşağıdaki gibi olacaktır

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

Bakın ne oldu.

YEAR üzerinde Group By olmadan sayım yapabilir ve ROW ile eşleştirebilirsiniz.

Başka bir ilginç yol aynı sonucu elde etmek için aşağıdaki yan tümce kullanarak, İLE satır içi görünüm olarak çalışır ve özellikle karmaşık olanları sorgu basitleştirebilir, sadece burada göstermek için çalışıyorum beri burada durum böyle değil

 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

OVER yan tümcesi, PARTITION BY ile birleştirildiğinde, önceki işlev çağrısının, sorgunun döndürülen satırları değerlendirilerek analitik olarak yapılması gerektiğini belirtir. Bunu satır içi GROUP BY deyimi olarak düşünün.

OVER (PARTITION BY SalesOrderID) SUM, AVG, etc ... işlevi için, sorgudan döndürülen kayıtların bir alt kümesinin OVER değerini ve yabancı anahtar SalesOrderID BY alt kümesini içeren PARTITION değerini döndürdüğünü belirtir.

Bu nedenle, EACH UNIQUE SalesOrderID için her OrderQty kaydını TOPLUYORUZ ve bu sütun adı 'Toplam' olarak adlandırılacaktır.

Aynı bilgileri bulmak için birden çok satır içi görünüm kullanmaktan çok daha etkili bir yöntemdir. Bu sorguyu bir satır içi görünüm içine yerleştirebilir ve Toplam'a filtre uygulayabilirsiniz.

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

2
  • Ayrıca Query PetitionMadde.
  • Group ByFıkra benzer

    • verileri parçalara (veya bölümlere) ayırma
    • bölüm sınırlarına göre ayır
    • işlevi bölümler içinde gerçekleştirir
    • ayrılık sınırını geçerken yeniden başlatılır

Sözdizimi:
function (...) OVER (PARTITION BY col1 col3, ...)

  • Fonksiyonlar

    • Gibi Tanıdık fonksiyonlar COUNT(), SUM(), MIN(), MAX(), vb
    • Yeni İşlevler de (ör ROW_NUMBER(). RATION_TO_REOIRT(), Vb.)


Örnekle daha fazla bilgi: http://msdn.microsoft.com/en-us/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

Bu sorgulamanın bir sonucudur. Kaynak olarak kullanılan tablo, son sütunu olmamasıyla aynıdır. Bu sütun, üçüncü sütunun hareketli toplamıdır.

Sorgu:

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

(tablo herkese açıktır. iuk)

sql version:  2012

Dbase (1986) seviyesinin biraz üzerinde, neden bitirmek için 25 yıldan fazla süreye ihtiyaç duyulduğunu bilmiyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.