Zoeken…


parameters

Parameter Details
PARTITIE DOOR De veld (en) die op PARTITION BY volgen, is het veld waarop de 'groepering' zal worden gebaseerd

Opmerkingen

De clausule OVER bepaalt een venster of een subset van een rij binnen een set met queryresultaten. Een vensterfunctie kan worden toegepast om een waarde in te stellen en te berekenen voor elke rij in de set. De clausule OVER kan worden gebruikt met:

  • Rangorde functies
  • Geaggregeerde functies

zodat iemand geaggregeerde waarden kan berekenen, zoals voortschrijdende gemiddelden, cumulatieve aggregaten, lopende totalen of een top N per groepsresultaten.

Op een zeer abstracte manier kunnen we zeggen dat OVER zich gedraagt als GROEP DOOR. OVER wordt echter toegepast per veld / kolom en niet op de query als geheel zoals GROUP BY.

Opmerking # 1: In SQL Server 2008 (R2) ORDER BY Clausule kan niet worden gebruikt met geaggregeerde vensterfuncties ( link ).

Aggregatiefuncties gebruiken met OVER

Aan de hand van de tabel Auto's berekenen we het totale, maximale, minimale en gemiddelde geldbedrag dat elke klant heeft uitgegeven en we hebben meerdere keren (COUNT) meegenomen voor reparatie.

Id Klant-id MechanicId Model Status Totale kosten

SELECT CustomerId,  
       SUM(TotalCost) OVER(PARTITION BY CustomerId) AS Total,
       AVG(TotalCost) OVER(PARTITION BY CustomerId) AS Avg,
       COUNT(TotalCost) OVER(PARTITION BY CustomerId) AS Count,
       MIN(TotalCost) OVER(PARTITION BY CustomerId) AS Min,
       MAX(TotalCost) OVER(PARTITION BY CustomerId) AS Max
  FROM CarsTable
 WHERE Status = 'READY'

Houd er rekening mee dat het gebruik van OVER op deze manier de geretourneerde rijen niet verzamelt. De bovenstaande zoekopdracht retourneert het volgende:

Klanten ID Totaal Gem tellen min Max
1 430 215 2 200 230
1 430 215 2 200 230

De dubbele rij (en) zijn mogelijk niet zo handig voor rapportagedoeleinden.

Als u gewoon gegevens wilt verzamelen, kunt u beter de GROUP BY-clausule gebruiken in combinatie met de juiste aggregatiefuncties, bijvoorbeeld:

SELECT CustomerId,  
       SUM(TotalCost) AS Total,
       AVG(TotalCost) AS Avg,
       COUNT(TotalCost) AS Count,
       MIN(TotalCost) AS Min,
       MAX(TotalCost)  AS Max
  FROM CarsTable
 WHERE Status = 'READY'
GROUP BY CustomerId

Cumulatieve som

Met behulp van de artikelverkooptabel proberen we erachter te komen hoe de verkoop van onze artikelen stijgt door de datums. Hiertoe berekenen we de cumulatieve som van de totale omzet per artikelorder op de verkoopdatum.

SELECT item_id, sale_Date 
       SUM(quantity * price) OVER(PARTITION BY item_id ORDER BY sale_Date ROWS BETWEEN UNBOUNDED PRECEDING) AS SalesTotal
  FROM SalesTable

Aggregatiefuncties gebruiken om de meest recente records te vinden

Met behulp van de bibliotheekdatabase proberen we voor elke auteur het laatste boek te vinden dat aan de database is toegevoegd. Voor dit eenvoudige voorbeeld gaan we uit van een altijd toenemende ID voor elke toegevoegde record.

SELECT MostRecentBook.Name, MostRecentBook.Title
FROM ( SELECT Authors.Name,
              Books.Title,
              RANK() OVER (PARTITION BY Authors.Id ORDER BY Books.Id DESC) AS NewestRank
       FROM Authors
       JOIN Books ON Books.AuthorId = Authors.Id
     ) MostRecentBook
WHERE MostRecentBook.NewestRank = 1

In plaats van RANK kunnen twee andere functies worden gebruikt om te bestellen. In het vorige voorbeeld is het resultaat hetzelfde, maar ze geven verschillende resultaten wanneer de volgorde meerdere rijen voor elke rang geeft.

  • RANK() : duplicaten krijgen dezelfde rang, de volgende rang houdt rekening met het aantal duplicaten in de vorige rang
  • DENSE_RANK() : duplicaten krijgen dezelfde rang, de volgende rang is altijd één hoger dan de vorige
  • ROW_NUMBER() : geeft elke rij een unieke 'rang', waarbij de duplicaten willekeurig worden 'geclassificeerd'

Als de tabel bijvoorbeeld een niet-unieke kolom CreationDate had en de bestelling op basis daarvan was gedaan, de volgende query:

SELECT Authors.Name,
       Books.Title,
       Books.CreationDate,
       RANK() OVER (PARTITION BY Authors.Id ORDER BY Books.CreationDate DESC) AS RANK,
       DENSE_RANK() OVER (PARTITION BY Authors.Id ORDER BY Books.CreationDate DESC) AS DENSE_RANK,
       ROW_NUMBER() OVER (PARTITION BY Authors.Id ORDER BY Books.CreationDate DESC) AS ROW_NUMBER,
FROM Authors
JOIN Books ON Books.AuthorId = Authors.Id

Kan resulteren in:

Auteur Titel Aanmaakdatum RANG DENSE_RANK RIJ NUMMER
Auteur 1 Boek 1 22/07/2016 1 1 1
Auteur 1 Boek 2 22/07/2016 1 1 2
Auteur 1 Boek 3 21/07/2016 3 2 3
Auteur 1 Boek 4 21/07/2016 3 2 4
Auteur 1 Boek 5 21/07/2016 3 2 5
Auteur 1 Boek 6 2016/04/07 6 3 6
Auteur 2 Boek 7 2016/04/07 1 1 1

Gegevens verdelen in emmers met gelijke verdeling met behulp van NTILE

Laten we zeggen dat u examenscores hebt voor verschillende examens en u deze per examen in kwartielen wilt verdelen.

-- Setup data:
declare @values table(Id int identity(1,1) primary key, [Value] float, ExamId int)
insert into @values ([Value], ExamId) values
(65, 1), (40, 1), (99, 1), (100, 1), (90, 1), -- Exam 1 Scores
(91, 2), (88, 2), (83, 2), (91, 2), (78, 2), (67, 2), (77, 2) -- Exam 2 Scores

-- Separate into four buckets per exam:
select ExamId, 
       ntile(4) over (partition by ExamId order by [Value] desc) as Quartile, 
       Value, Id 
from @values 
order by ExamId, Quartile

Onze examengegevens zijn verdeeld in kwartielen per examen

ntile werkt geweldig als je echt een bepaald aantal emmers nodig hebt en elk tot ongeveer hetzelfde niveau gevuld. Merk op dat het triviaal zou zijn om deze scores in percentielen te scheiden door eenvoudig ntile(100) .



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow