Window Frames
Ein Fensterrahmen (window frame) gibt an, welche Zeilen für die aktuelle Zeile bei der Auswertung der Fensterfunktion berücksichtigt werden sollen.
Der Rahmen besteht aus drei Teilen: Einheit, Anfangsbindung und Endbindung.Die Einheit kann RANGE oder ROWS sein, die definiert, wie die Grenzen funktionieren.
Die Grenzen sind:
-
<expr> PRECEDING -
<expr> FOLLOWING -
CURRENT ROW
-
Bei
RANGEsollteORDER BYgenau einen Ausdruck angeben, und dieser Ausdruck sollte numerisch, Datum, Uhrzeit oder Zeitstempel sein.Für<expr> PRECEDINGwird expr vomORDER BYAusdruck abgezogen und für<expr> FOLLOWINGwird expr hinzugefügt.FürCURRENT ROWwird der Ausdruck unverändert verwendet.Alle Zeilen innerhalb der aktuellen Partition, die sich zwischen den Grenzen befinden, werden als Teil des resultierenden Fensterrahmens betrachtet.
-
Bei
ROWSsindORDER BY-Ausdrücke nicht durch Anzahl oder Typ beschränkt.Für diese Einheit beziehen sich<expr> PRECEDINGund<expr FOLLOWINGauf die Zeilenposition innerhalb der aktuellen Partition und nicht auf die Werte der Sortierschlüssel.
Sowohl UNBOUNDED PRECEDING als auch UNBOUNDED FOLLOWING funktionieren identisch mit RANGE und ROWS.UNBOUNDED PRECEDING beginnt in der ersten Zeile der aktuellen Partition und UNBOUNDED FOLLOWING in der letzten Zeile der aktuellen Partition.
Die Frame-Syntax mit <window_frame_start> spezifiziert den Start-Frame, wobei der End-Frame `CURRENT ROW ist.
Einige Window-Funktionen verwerfen Frames:
-
ROW_NUMBER,LAGundLEADfunktionieren immer alsROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW -
DENSE_RANK,RANK,PERCENT_RANKundCUME_DISTfunktionieren immer alsRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW -
FIRST_VALUE,LAST_VALUEundNTH_VALUErespektieren Frames, aber das Verhalten derRANGE-Einheit ist identisch mitROWS.
Beispiel für die Verwendung von Frame
Wenn die ORDER BY-Klausel verwendet wird, aber eine Frame-Klausel weggelassen wird, berücksichtigt die Standardeinstellung die Partition bis zur aktuellen Zeile.In Kombination mit SUM ergibt dies eine laufende Summe:
select
id,
salary,
sum(salary) over (order by salary) sum_salary
from employee
order by salary;
Ergebnis:
| id | salary | sum_salary |
|---:|-------:|-----------:|
| 3 | 8.00 | 8.00 |
| 4 | 9.00 | 17.00 |
| 1 | 10.00 | 37.00 |
| 5 | 10.00 | 37.00 |
| 2 | 12.00 | 49.00 |
Wenn wir dagegen einen Rahmen für die gesamte Partition anwenden, erhalten wir die Summe für die gesamte Partition.
select
id,
salary,
sum(salary) over (
order by salary
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) sum_salary
from employee
order by salary;
Ergebnis:
| id | salary | sum_salary |
|---:|-------:|-----------:|
| 3 | 8.00 | 49.00 |
| 4 | 9.00 | 49.00 |
| 1 | 10.00 | 49.00 |
| 5 | 10.00 | 49.00 |
| 2 | 12.00 | 49.00 |
Dieses Beispiel soll nur demonstrieren, wie dies funktioniert;das Ergebnis dieses speziellen Beispiels wäre einfacher mit sum(salary) over() zu erzeugen.
Mit dieser Abfrage können wir einen Bereichsrahmen verwenden, um die Anzahl der Mitarbeiter mit Gehältern zwischen (Gehalt eines Mitarbeiters - 1) und (Gehalt + 1) zu berechnen:
select
id,
salary,
count(*) over (
order by salary
RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING
) range_count
from employee
order by salary;
Ergebnis:
| id | salary | range_count |
|---:|-------:|------------:|
| 3 | 8.00 | 2 |
| 4 | 9.00 | 4 |
| 1 | 10.00 | 3 |
| 5 | 10.00 | 3 |
| 2 | 12.00 | 1 |