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
RANGE
sollteORDER BY
genau einen Ausdruck angeben, und dieser Ausdruck sollte numerisch, Datum, Uhrzeit oder Zeitstempel sein.Für<expr> PRECEDING
wird expr vomORDER BY
Ausdruck abgezogen und für<expr> FOLLOWING
wird expr hinzugefügt.FürCURRENT ROW
wird 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
ROWS
sindORDER BY
-Ausdrücke nicht durch Anzahl oder Typ beschränkt.Für diese Einheit beziehen sich<expr> PRECEDING
und<expr FOLLOWING
auf 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
,LAG
undLEAD
funktionieren immer alsROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
-
DENSE_RANK
,RANK
,PERCENT_RANK
undCUME_DIST
funktionieren immer alsRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
-
FIRST_VALUE
,LAST_VALUE
undNTH_VALUE
respektieren 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 |