Syntax und Verwendung von Fensterfunktionen

Unter diesem Thema:

Snowflake unterstützt eine große Anzahl von analytischen SQL-Funktionen, die als Fensterfunktionen bekannt sind. Die Details für jede Funktion sind auf den einzelnen Referenzseiten dokumentiert. Der Zweck dieses Abschnitts besteht darin, allgemeine Referenzinformationen bereitzustellen, die für einige oder alle Fensterfunktionen gelten, einschließlich einer detaillierten Syntax für die Hauptkomponenten der OVER-Klausel:

  • PARTITION BY-Klausel.

  • ORDER BY-Klausel.

  • Fensterrahmensyntax

Benutzer, die mit Fensterfunktionen nicht vertraut sind, sollten sich erst mit dem Konzept vertraut machen, das unter Analysieren von Daten mit Fensterfunktionen beschrieben wird.

Syntax

<function> ( [ <arguments> ] ) OVER ( [ <windowDefinition> ] )
Copy

Wobei:

windowDefinition ::=

[ PARTITION BY <expr1> [, ...] ]
[ ORDER BY <expr2> [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] ]
[ <windowFrameClause> ]
Copy

Wobei:

windowFrameClause ::=

{
    { ROWS | RANGE } UNBOUNDED PRECEDING
  | { ROWS | RANGE } <n> PRECEDING
  | { ROWS | RANGE } CURRENT ROW
  | { ROWS | RANGE } BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
  | { ROWS | RANGE } BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
  | { ROWS | RANGE } BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
  | { ROWS | RANGE } BETWEEN <n> { PRECEDING | FOLLOWING } AND <n> { PRECEDING | FOLLOWING }
  | { ROWS | RANGE } BETWEEN UNBOUNDED PRECEDING AND <n> { PRECEDING | FOLLOWING }
  | { ROWS | RANGE } BETWEEN <n> { PRECEDING | FOLLOWING } AND UNBOUNDED FOLLOWING
}
Copy

Parameter

OVER( [ windowDefinition ] )

Gibt an, dass die Funktion als Fensterfunktion verwendet wird und gibt das Fenster an, über das die Funktion operiert. Die OVER-Klause muss Klammern enthalten, die jedoch je nach Anforderungen der betreffenden Funktion auch leer sein können. Eine leere OVER-Klausel hat keine Partitionen und einen impliziten Standard-Fensterrahmen.

PARTITION BY expr1

Gruppiert Zeilen in Partitionen, z. B. nach Produkt, Stadt oder Jahr. Die eingegebenen Zeilen werden nach Partitionen gruppiert, dann wird die Funktion über jede Partition berechnet. Die PARTITION BY-Klausel ist optional. Sie können eine Gruppe von Zeilen als eine einzige Partition analysieren.

ORDER BY expr2

Sortiert die Zeilen innerhalb jeder Partition oder innerhalb des gesamten Zeilensatzes, wenn keine Partition angegeben ist. Diese ORDER BY-Klausel unterscheidet sich von der ORDER BY-Klausel, die die Reihenfolge aller Zeilen steuert, die im Endergebnis einer Abfrage zurückgegeben werden. Obwohl die ORDER BY-Klausel für einige Fensterfunktionen optional ist, ist sie für andere erforderlich. Zum Beispiel erfordern Ranking-Fensterfunktionen wie RANK und NTILE, dass ihre Eingabedaten in einer sinnvollen Reihenfolge vorliegen.

Die ORDER BY-Klausel für eine Fensterfunktion folgt ähnlichen Regeln wie die ORDER BY-Hauptklausel in einer Abfrage, was die Reihenfolge ASC/DESC (aufsteigend/absteigend) und die Behandlung von NULL betrifft. Weitere Details dazu finden Sie unter ORDER BY.

Verschiedene Funktionen behandeln die ORDER BY-Klausel auf unterschiedliche Weise:

  • Einige Fensterfunktionen erfordern eine ORDER BY-Klausel.

  • Einige Fensterfunktionen verbieten eine ORDER BY-Klausel.

  • Einige Fensterfunktionen verwenden eine ORDER BY-Klausel, wenn eine vorhanden ist, benötigen diese jedoch nicht.

  • Einige Fensterfunktionen wenden einen impliziten Fensterrahmen auf die ORDER BY-Klausel an. (Weitere Informationen dazu finden Sie unter Nutzungshinweise für Fensterrahmen.)

{ ROWS | RANGE }

Gibt den Typ oder Modus des Fensterrahmens an, der entweder eine physische Anzahl von Zeilen (ROWS) oder eine logisch berechnete Menge von Zeilen (RANGE) definiert. Siehe Rangbezogene versus zeilenbezogene Fensterrahmen.

Beide Arten von Rahmen legen Anfangs- und Endpunkte fest, wobei entweder implizite benannte Grenzen oder explizite Offset-Werte verwendet werden. Eine benannte Begrenzung wird mit den Schlüsselwörtern CURRENT ROW, UNBOUNDED PRECEDING und UNBOUNDED FOLLOWING definiert. Explizite Offsets werden mit Zahlen oder Intervallen (n PRECEDING oder n FOLLOWING) definiert.

{ RANGE BETWEEN n PRECEDING | n FOLLOWING }

Gibt einen rangbezogenen Fensterrahmen mit expliziten Offsets an.

RANGE BETWEEN-Fensterrahmen mit expliziten Offsets dürfen nur einen ORDER BY-Ausdruck haben. Die folgenden Datentypen werden für diesen Ausdruck unterstützt:

  • DATE, TIMESTAMP, TIMESTAMP_LTZ , TIMESTAMP_NTZ (DATETIME) , TIMESTAMP_TZ

  • NUMBER, einschließlich INT, FLOAT und so weiter

TIME und andere Snowflake-Datentypen werden nicht unterstützt, wenn dieser Typ von Fensterrahmen verwendet wird. Für andere Fensterrahmen können andere Datentypen, wie z. B. VARCHAR im ORDER BY-Ausdruck verwendet werden.

Für RANGE BETWEEN-Fensterrahmen muss n eine Konstante ohne Vorzeichen (ein positiver numerischer Wert, einschließlich 0) oder eine positive INTERVAL-Konstante sein:

  • Wenn expr2 ein numerischer Datentyp ist, muss n eine Konstante ohne Vorzeichen sein.

  • Wenn expr2 ein TIMESTAMP-Datentyp ist, muss n eine INTERVAL-Konstante sein. Beispiel: INTERVAL '12 hours' oder INTERVAL '3 days'

  • Wenn expr2 ein DATE-Datentyp ist, kann n eine Konstante ohne Vorzeichen oder eine INTERVAL-Konstante sein, aber der Anfang und das Ende des Rahmens müssen denselben Datentyp für den Wert n verwenden.

Wenn der Ausdruck ORDER BY aufsteigend ist (ASC), bedeutet die Syntax n FOLLOWING „Zeilen mit Werten größer als (oder später als) x “, und n PRECEDING bedeutet „Zeilen mit Werten kleiner als (oder früher als) x “, wobei x der ORDER BY-Wert für die aktuelle Zeile ist. Wenn der ORDER BY-Ausdruck absteigend ist (DESC), ist das Gegenteil der Fall. (Die Offsets 0 PRECEDING und 0 FOLLOWING sind äquivalent zu CURRENT ROW. )

RANGE-BETWEEN-Einschränkungen

Die folgende Untergruppe von Fensterfunktionen unterstützt die RANGE BETWEEN-Syntax mit expliziten Offsets:

Beachten Sie darüber hinaus, dass:

  • DISTINCT-Versionen dieser Funktionen diese Syntax nicht unterstützen.

  • Die folgenden Beschränkungen gelten, wenn die Fensterfunktion COUNT mit dieser Syntax verwendet wird.

    • Es wird nur ein Eingabeargument unterstützt.

    • COUNT(table.*)-Platzhalterabfragen werden nicht unterstützt. Sie können zum Beispiel Folgendes nicht angeben:

      COUNT(t1.*) OVER(ORDER BY col1 RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING)
      
      Copy
  • Sie können keinen Rahmen angeben, der zu einer logischen Umkehrung der Start- und Endposition des Rahmens führt. Die folgenden Rahmen zum Beispiel Fehler zurück, weil die letzte Zeile des Rahmens vor der ersten Zeile liegt:

    ORDER BY col1 ASC RANGE BETWEEN 2 PRECEDING AND 4 PRECEDING
    ORDER BY col1 ASC RANGE BETWEEN 2 FOLLOWING AND 2 PRECEDING
    
    Copy

RANGE BETWEEN-Verhaltensweise, wenn der Ausdruck ORDER BY-Ausdruck NULL-Werte enthält

Beachten Sie die folgende Verhaltensweise, wenn ein Fensterrahmen RANGE BETWEEN verwendet wird und die ORDER BY-Spalte NULL-Werte enthält:

  • Wenn die ORDER BY-Klausel NULLS FIRST angibt, werden Zeilen mit NULL in der ORDER BY-Spalte in die UNBOUNDED PRECEDING-Rahmen aufgenommen.

  • Wenn die ORDER BY-Klausel NULLS LAST angibt, werden Zeilen mit NULL in der ORDER BY-Spalte in die UNBOUNDED FOLLOWING-Rahmen aufgenommen.

  • Zeilen mit NULL in der ORDER BY-Spalte werden nur dann in einen Rahmen mit explizitem Offset einbezogen, wenn der ORDER BY-Wert der aktuellen Zeile NULL ist.

Siehe Beispiele für RANGE BETWEEN mit NULL-Werten in der ORDER BY-Klausel.

Nutzungshinweise für Fensterrahmen

  • Alle Fensterfunktionen unterstützen Fensterrahmen. Die Unterstützung für die Syntax von Fensterrahmen variiert jedoch je nach Funktion. Wenn kein Fensterrahmen angegeben ist, hängt der Standard von der Funktion ab:

    • Für Funktionen, die nicht rangbezogen sind (wie COUNT, MAX, MIN und SUM), wird standardmäßig der folgende Fensterrahmen verwendet (gemäß dem ANSI-Standard):

      RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
      
      Copy
    • Bei rangbezogenen Funktionen (wie FIRST_VALUE, LAST_VALUE, NTH_VALUE) ist der Standard das gesamte Fenster:

      ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
      
      Copy

      Beachten Sie, dass diese Verhaltensweise nicht mit dem ANSI-Standard übereinstimmt.

      Bemerkung

      Snowflake empfiehlt, aus Gründen der Übersichtlichkeit auf implizite Fensterrahmen zu verzichten. Wenn Ihre Abfrage einen Fensterrahmen verwendet, definieren Sie einen expliziten Fensterrahmen.

  • Fensterrahmen erfordern, dass die Daten im Fenster in einer bekannten Reihenfolge vorliegen. Daher ist die ORDER BY-Klausel innerhalb der OVER Klausel für die Syntax des Fensterrahmens erforderlich, auch wenn die ORDER BY-Klausel im Allgemeinen optional ist.

Beispiele

Dieser Abschnitt enthält Beispiele, die zeigen, wie Fensterfunktionen auf unterschiedliche Weise verwendet werden können. Weitere Beispiele finden Sie unter Analysieren von Daten mit Fensterfunktionen und auf den Seiten für die einzelnen Funktionen.

Einführungsbeispiel

Angenommen, Sie besitzen eine Ladenkette. Die folgende Abfrage zeigt den prozentualen Anteil der einzelnen Filialen am Gesamtgewinn der Kette. Die Abfrage verwendet die Funktion RATIO_TO_REPORT, die einen Wert (net_profit) aus der aktuellen Zeile nimmt und ihn durch die Summe der entsprechenden Werte aus allen anderen Zeilen dividiert:

Erstellen und Laden der Tabelle:

CREATE TRANSIENT TABLE store_sales (
    branch_ID    INTEGER,
    city        VARCHAR,
    gross_sales NUMERIC(9, 2),
    gross_costs NUMERIC(9, 2),
    net_profit  NUMERIC(9, 2)
    );

INSERT INTO store_sales (branch_ID, city, gross_sales, gross_costs)
    VALUES
    (1, 'Vancouver', 110000, 100000),
    (2, 'Vancouver', 140000, 125000),
    (3, 'Montreal', 150000, 140000),
    (4, 'Montreal', 155000, 146000);

UPDATE store_sales SET net_profit = gross_sales - gross_costs;
Copy

Fragen Sie die Tabelle ab:

SELECT branch_ID,
       net_profit,
       100 * RATIO_TO_REPORT(net_profit) OVER () AS percent_of_chain_profit
    FROM store_sales AS s1
    ORDER BY branch_ID;
+-----------+------------+-------------------------+
| BRANCH_ID | NET_PROFIT | PERCENT_OF_CHAIN_PROFIT |
|-----------+------------+-------------------------|
|         1 |   10000.00 |             22.72727300 |
|         2 |   15000.00 |             34.09090900 |
|         3 |   10000.00 |             22.72727300 |
|         4 |    9000.00 |             20.45454500 |
+-----------+------------+-------------------------+
Copy

Fensterrahmen mit einer unbegrenzten Ausgangsposition

Erstellen Sie eine Tabelle, und füllen Sie diese mit Werten:

CREATE OR REPLACE TABLE example_cumulative (p INT, o INT, i INT);

INSERT INTO example_cumulative VALUES
    (  0, 1, 10), (0, 2, 20), (0, 3, 30),
    (100, 1, 10),(100, 2, 30),(100, 2, 5),(100, 3, 11),(100, 3, 120),
    (200, 1, 10000),(200, 1, 200),(200, 1, 808080),(200, 2, 33333),(200, 3, null), (200, 3, 4),
    (300, 1, null), (300, 1, null);
Copy

Führen Sie eine Abfrage aus, die einen Fensterrahmen mit einer unbegrenzten Ausgangsposition verwendet, und zeigen Sie die Ausgabe an. Ermitteln der kumulierten Werte COUNT, SUM, AVG, MIN und MAX für jede Zeile in jeder Partition zurück:

SELECT
    p, o, i,
    COUNT(i) OVER (PARTITION BY p ORDER BY o ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) count_i_Rows_Pre,
    SUM(i)   OVER (PARTITION BY p ORDER BY o ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) sum_i_Rows_Pre,
    AVG(i)   OVER (PARTITION BY p ORDER BY o ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) avg_i_Rows_Pre,
    MIN(i)   OVER (PARTITION BY p ORDER BY o ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) min_i_Rows_Pre,
    MAX(i)   OVER (PARTITION BY p ORDER BY o ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) max_i_Rows_Pre
  FROM example_cumulative
  ORDER BY p,o;
+-----+---+--------+------------------+----------------+----------------+----------------+----------------+
|   P | O |      I | COUNT_I_ROWS_PRE | SUM_I_ROWS_PRE | AVG_I_ROWS_PRE | MIN_I_ROWS_PRE | MAX_I_ROWS_PRE |
|-----+---+--------+------------------+----------------+----------------+----------------+----------------|
|   0 | 1 |     10 |                1 |             10 |         10.000 |             10 |             10 |
|   0 | 2 |     20 |                2 |             30 |         15.000 |             10 |             20 |
|   0 | 3 |     30 |                3 |             60 |         20.000 |             10 |             30 |
| 100 | 1 |     10 |                1 |             10 |         10.000 |             10 |             10 |
| 100 | 2 |     30 |                2 |             40 |         20.000 |             10 |             30 |
| 100 | 2 |      5 |                3 |             45 |         15.000 |              5 |             30 |
| 100 | 3 |     11 |                4 |             56 |         14.000 |              5 |             30 |
| 100 | 3 |    120 |                5 |            176 |         35.200 |              5 |            120 |
| 200 | 1 |  10000 |                1 |          10000 |      10000.000 |          10000 |          10000 |
| 200 | 1 |    200 |                2 |          10200 |       5100.000 |            200 |          10000 |
| 200 | 1 | 808080 |                3 |         818280 |     272760.000 |            200 |         808080 |
| 200 | 2 |  33333 |                4 |         851613 |     212903.250 |            200 |         808080 |
| 200 | 3 |   NULL |                4 |         851613 |     212903.250 |            200 |         808080 |
| 200 | 3 |      4 |                5 |         851617 |     170323.400 |              4 |         808080 |
| 300 | 1 |   NULL |                0 |           NULL |           NULL |           NULL |           NULL |
| 300 | 1 |   NULL |                0 |           NULL |           NULL |           NULL |           NULL |
+-----+---+--------+------------------+----------------+----------------+----------------+----------------+
Copy

Ermitteln derselben Ergebnisse wie in der obigen Abfrage aber durch Verwendung des Standard-Fensterrahmens (d. h. ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW):

SELECT
    p, o, i,
    COUNT(i) OVER (PARTITION BY p ORDER BY o) count_i_Range_Pre,
    SUM(i)   OVER (PARTITION BY p ORDER BY o) sum_i_Range_Pre,
    AVG(i)   OVER (PARTITION BY p ORDER BY o) avg_i_Range_Pre,
    MIN(i)   OVER (PARTITION BY p ORDER BY o) min_i_Range_Pre,
    MAX(i)   OVER (PARTITION BY p ORDER BY o) max_i_Range_Pre
  FROM example_cumulative
  ORDER BY p,o;
+-----+---+--------+-------------------+-----------------+-----------------+-----------------+-----------------+
|   P | O |      I | COUNT_I_RANGE_PRE | SUM_I_RANGE_PRE | AVG_I_RANGE_PRE | MIN_I_RANGE_PRE | MAX_I_RANGE_PRE |
|-----+---+--------+-------------------+-----------------+-----------------+-----------------+-----------------|
|   0 | 1 |     10 |                 1 |              10 |       10.000000 |              10 |              10 |
|   0 | 2 |     20 |                 2 |              30 |       15.000000 |              10 |              20 |
|   0 | 3 |     30 |                 3 |              60 |       20.000000 |              10 |              30 |
| 100 | 1 |     10 |                 1 |              10 |       10.000000 |              10 |              10 |
| 100 | 2 |     30 |                 3 |              45 |       15.000000 |               5 |              30 |
| 100 | 2 |      5 |                 3 |              45 |       15.000000 |               5 |              30 |
| 100 | 3 |     11 |                 5 |             176 |       35.200000 |               5 |             120 |
| 100 | 3 |    120 |                 5 |             176 |       35.200000 |               5 |             120 |
| 200 | 1 |  10000 |                 3 |          818280 |   272760.000000 |             200 |          808080 |
| 200 | 1 |    200 |                 3 |          818280 |   272760.000000 |             200 |          808080 |
| 200 | 1 | 808080 |                 3 |          818280 |   272760.000000 |             200 |          808080 |
| 200 | 2 |  33333 |                 4 |          851613 |   212903.250000 |             200 |          808080 |
| 200 | 3 |   NULL |                 5 |          851617 |   170323.400000 |               4 |          808080 |
| 200 | 3 |      4 |                 5 |          851617 |   170323.400000 |               4 |          808080 |
| 300 | 1 |   NULL |                 0 |            NULL |            NULL |            NULL |            NULL |
| 300 | 1 |   NULL |                 0 |            NULL |            NULL |            NULL |            NULL |
+-----+---+--------+-------------------+-----------------+-----------------+-----------------+-----------------+
Copy

Fensterrahmen mit expliziten Offsets

Erstellen Sie eine Tabelle, und füllen Sie diese mit Werten:

CREATE TABLE example_sliding
  (p INT, o INT, i INT, r INT, s VARCHAR(100));

INSERT INTO example_sliding VALUES
  (100,1,1,70,'seventy'),(100,2,2,30, 'thirty'),(100,3,3,40,'forty'),(100,4,NULL,90,'ninety'),
  (100,5,5,50,'fifty'),(100,6,6,30,'thirty'),
  (200,7,7,40,'forty'),(200,8,NULL,NULL,'n_u_l_l'),(200,9,NULL,NULL,'n_u_l_l'),(200,10,10,20,'twenty'),
  (200,11,NULL,90,'ninety'),
  (300,12,12,30,'thirty'),
  (400,13,NULL,20,'twenty');
Copy

Ermitteln Ergebnisse MIN-Funktion für zwei Spalten (numerisch und Zeichenfolge) über gleitende Fenster vor, nach und um die aktuelle Zeile:

select p, o, i AS i_col,
    MIN(i) OVER (PARTITION BY p ORDER BY o ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING) min_i_3P_1P,
    MIN(i) OVER (PARTITION BY p ORDER BY o ROWS BETWEEN 1 FOLLOWING AND 3 FOLLOWING) min_i_1F_3F,
    MIN(i) OVER (PARTITION BY p ORDER BY o ROWS BETWEEN 1 PRECEDING AND 3 FOLLOWING) min_i_1P_3F,
    s,
    MIN(s) OVER (PARTITION BY p ORDER BY o ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING) min_s_3P_1P,
    MIN(s) OVER (PARTITION BY p ORDER BY o ROWS BETWEEN 1 FOLLOWING AND 3 FOLLOWING) min_s_1F_3F,
    MIN(s) OVER (PARTITION BY p ORDER BY o ROWS BETWEEN 1 PRECEDING AND 3 FOLLOWING) min_s_1P_3F
  FROM example_sliding
  ORDER BY p, o;
+-----+----+-------+-------------+-------------+-------------+---------+-------------+-------------+-------------+
|   P |  O | I_COL | MIN_I_3P_1P | MIN_I_1F_3F | MIN_I_1P_3F | S       | MIN_S_3P_1P | MIN_S_1F_3F | MIN_S_1P_3F |
|-----+----+-------+-------------+-------------+-------------+---------+-------------+-------------+-------------|
| 100 |  1 |     1 |        NULL |           2 |           1 | seventy | NULL        | forty       | forty       |
| 100 |  2 |     2 |           1 |           3 |           1 | thirty  | seventy     | fifty       | fifty       |
| 100 |  3 |     3 |           1 |           5 |           2 | forty   | seventy     | fifty       | fifty       |
| 100 |  4 |  NULL |           1 |           5 |           3 | ninety  | forty       | fifty       | fifty       |
| 100 |  5 |     5 |           2 |           6 |           5 | fifty   | forty       | thirty      | fifty       |
| 100 |  6 |     6 |           3 |        NULL |           5 | thirty  | fifty       | NULL        | fifty       |
| 200 |  7 |     7 |        NULL |          10 |           7 | forty   | NULL        | n_u_l_l     | forty       |
| 200 |  8 |  NULL |           7 |          10 |           7 | n_u_l_l | forty       | n_u_l_l     | forty       |
| 200 |  9 |  NULL |           7 |          10 |          10 | n_u_l_l | forty       | ninety      | n_u_l_l     |
| 200 | 10 |    10 |           7 |        NULL |          10 | twenty  | forty       | ninety      | n_u_l_l     |
| 200 | 11 |  NULL |          10 |        NULL |          10 | ninety  | n_u_l_l     | NULL        | ninety      |
| 300 | 12 |    12 |        NULL |        NULL |          12 | thirty  | NULL        | NULL        | thirty      |
| 400 | 13 |  NULL |        NULL |        NULL |        NULL | twenty  | NULL        | NULL        | twenty      |
+-----+----+-------+-------------+-------------+-------------+---------+-------------+-------------+-------------+
Copy

Ermitteln Ergebnisse MAX-Funktion für zwei Spalten (numerisch und Zeichenfolge) über gleitende Fenster vor, nach und um die aktuelle Zeile:

SELECT p, o, i AS i_col,
    MAX(i) OVER (PARTITION BY p ORDER BY o ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING) max_i_3P_1P,
    MAX(i) OVER (PARTITION BY p ORDER BY o ROWS BETWEEN 1 FOLLOWING AND 3 FOLLOWING) max_i_1F_3F,
    MAX(i) OVER (PARTITION BY p ORDER BY o ROWS BETWEEN 1 PRECEDING AND 3 FOLLOWING) max_i_1P_3F,
    s,
    MAX(s) OVER (PARTITION BY p ORDER BY o ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING) max_s_3P_1P,
    MAX(s) OVER (PARTITION BY p ORDER BY o ROWS BETWEEN 1 FOLLOWING AND 3 FOLLOWING) max_s_1F_3F,
    MAX(s) OVER (PARTITION BY p ORDER BY o ROWS BETWEEN 1 PRECEDING AND 3 FOLLOWING) max_s_1P_3F
  FROM example_sliding
  ORDER BY p, o;
+-----+----+-------+-------------+-------------+-------------+---------+-------------+-------------+-------------+
|   P |  O | I_COL | MAX_I_3P_1P | MAX_I_1F_3F | MAX_I_1P_3F | S       | MAX_S_3P_1P | MAX_S_1F_3F | MAX_S_1P_3F |
|-----+----+-------+-------------+-------------+-------------+---------+-------------+-------------+-------------|
| 100 |  1 |     1 |        NULL |           3 |           3 | seventy | NULL        | thirty      | thirty      |
| 100 |  2 |     2 |           1 |           5 |           5 | thirty  | seventy     | ninety      | thirty      |
| 100 |  3 |     3 |           2 |           6 |           6 | forty   | thirty      | thirty      | thirty      |
| 100 |  4 |  NULL |           3 |           6 |           6 | ninety  | thirty      | thirty      | thirty      |
| 100 |  5 |     5 |           3 |           6 |           6 | fifty   | thirty      | thirty      | thirty      |
| 100 |  6 |     6 |           5 |        NULL |           6 | thirty  | ninety      | NULL        | thirty      |
| 200 |  7 |     7 |        NULL |          10 |          10 | forty   | NULL        | twenty      | twenty      |
| 200 |  8 |  NULL |           7 |          10 |          10 | n_u_l_l | forty       | twenty      | twenty      |
| 200 |  9 |  NULL |           7 |          10 |          10 | n_u_l_l | n_u_l_l     | twenty      | twenty      |
| 200 | 10 |    10 |           7 |        NULL |          10 | twenty  | n_u_l_l     | ninety      | twenty      |
| 200 | 11 |  NULL |          10 |        NULL |          10 | ninety  | twenty      | NULL        | twenty      |
| 300 | 12 |    12 |        NULL |        NULL |          12 | thirty  | NULL        | NULL        | thirty      |
| 400 | 13 |  NULL |        NULL |        NULL |        NULL | twenty  | NULL        | NULL        | twenty      |
+-----+----+-------+-------------+-------------+-------------+---------+-------------+-------------+-------------+
Copy

Ermitteln der Summe einer Zahlenspalte in gleitenden Fenstern vor, nach und um die aktuelle Zeile:

SELECT p, o, r AS r_col,
    SUM(r) OVER (PARTITION BY p ORDER BY o ROWS BETWEEN 4 PRECEDING AND 2 PRECEDING) sum_r_4P_2P,
    sum(r) over (partition by p ORDER BY o ROWS BETWEEN 2 FOLLOWING AND 4 FOLLOWING) sum_r_2F_4F,
    sum(r) over (partition by p ORDER BY o ROWS BETWEEN 2 PRECEDING AND 4 FOLLOWING) sum_r_2P_4F
  FROM example_sliding
  ORDER BY p, o;
+-----+----+-------+-------------+-------------+-------------+
|   P |  O | R_COL | SUM_R_4P_2P | SUM_R_2F_4F | SUM_R_2P_4F |
|-----+----+-------+-------------+-------------+-------------|
| 100 |  1 |    70 |        NULL |         180 |         280 |
| 100 |  2 |    30 |        NULL |         170 |         310 |
| 100 |  3 |    40 |          70 |          80 |         310 |
| 100 |  4 |    90 |         100 |          30 |         240 |
| 100 |  5 |    50 |         140 |        NULL |         210 |
| 100 |  6 |    30 |         160 |        NULL |         170 |
| 200 |  7 |    40 |        NULL |         110 |         150 |
| 200 |  8 |  NULL |        NULL |         110 |         150 |
| 200 |  9 |  NULL |          40 |          90 |         150 |
| 200 | 10 |    20 |          40 |        NULL |         110 |
| 200 | 11 |    90 |          40 |        NULL |         110 |
| 300 | 12 |    30 |        NULL |        NULL |          30 |
| 400 | 13 |    20 |        NULL |        NULL |          20 |
+-----+----+-------+-------------+-------------+-------------+
Copy

Beispiele für rangbezogene Funktionen

Das folgende Beispiel zeigt, wie die Rangfolge der Vertriebsmitarbeiter nach dem Gesamtverkaufsbetrag (in US-Dollar) erstellt wird. Die ORDER BY-Klausel innerhalb der OVER-Klausel sortiert die Summen in absteigender Reihenfolge (von der höchsten bis zur niedrigsten). Die Abfrage berechnet dann den Rang jedes Vertriebsmitarbeiters im Verhältnis zu den anderen Vertriebsmitarbeitern.

Erstellen Sie die Tabelle und fügen Sie die Daten ein:

CREATE TABLE sales_table (salesperson_name VARCHAR, sales_in_dollars INTEGER);
INSERT INTO sales_table (salesperson_name, sales_in_dollars) VALUES
    ('Smith', 600),
    ('Jones', 1000),
    ('Torkelson', 700),
    ('Dolenz', 800);
Copy

Fragen Sie jetzt die Daten ab:

SELECT
    salesperson_name,
    sales_in_dollars,
    RANK() OVER (ORDER BY sales_in_dollars DESC) AS sales_rank
  FROM sales_table;
+------------------+------------------+------------+
| SALESPERSON_NAME | SALES_IN_DOLLARS | SALES_RANK |
|------------------+------------------+------------|
| Jones            |             1000 |          1 |
| Dolenz           |              800 |          2 |
| Torkelson        |              700 |          3 |
| Smith            |              600 |          4 |
+------------------+------------------+------------+
Copy

Die Ausgabe ist nicht notwendigerweise nach Rang sortiert. Um die Ergebnisse nach Rang sortiert anzuzeigen, geben Sie eine ORDER BY-Klausel für die Abfrage selbst an (zusätzlich zur ORDER BY-Klausel für die Fensterfunktion), wie hier gezeigt:

SELECT
    salesperson_name,
    sales_in_dollars,
    RANK() OVER (ORDER BY sales_in_dollars DESC) AS sales_rank
  FROM sales_table
  ORDER BY 3;
+------------------+------------------+------------+
| SALESPERSON_NAME | SALES_IN_DOLLARS | SALES_RANK |
|------------------+------------------+------------|
| Jones            |             1000 |          1 |
| Dolenz           |              800 |          2 |
| Torkelson        |              700 |          3 |
| Smith            |              600 |          4 |
+------------------+------------------+------------+
Copy

Das vorangegangene Beispiel hat zwei ORDER BY-Klauseln:

  • Eine steuert die Reihenfolge des Rankings.

  • Die andere steuert die Reihenfolge für die Ausgabe.

Beide Klauseln sind unabhängig voneinander. So können Sie beispielsweise die Rangfolgen auf Basis des Gesamtumsatzes (wie oben beschrieben) ermitteln, aber die Ausgabezeilen auf Basis des Nachnamens des Verkäufers sortieren:

SELECT
    salesperson_name,
    sales_in_dollars,
    RANK() OVER (ORDER BY sales_in_dollars DESC) AS sales_rank
  FROM sales_table
  ORDER BY salesperson_name;
+------------------+------------------+------------+
| SALESPERSON_NAME | SALES_IN_DOLLARS | SALES_RANK |
|------------------+------------------+------------|
| Dolenz           |              800 |          2 |
| Jones            |             1000 |          1 |
| Smith            |              600 |          4 |
| Torkelson        |              700 |          3 |
+------------------+------------------+------------+
Copy

Beispiel für RANGE BETWEEN mit expliziten numerischen Offsets

Das folgende Beispiel verwendet die RANGE BETWEEN-Syntax mit expliziten numerischen Offsets. Um dieses Beispiel auszuführen, befolgen Sie die folgenden Anweisungen: Erstellen und Laden der „menu_items“-Tabelle. Ähnliche Beispiele, die INTERVAL-Offsets verwenden, finden Sie unter Verwenden von fensterbasierten Aggregationen für fortlaufende Berechnungen.

Die folgende Abfrage berechnet die durchschnittlichen Kosten der verkauften Waren für Kategorien von Menüartikeln, die in einem Imbisswagen erhältlich sind. Die Fensterfunktion partitioniert die Resultset nicht. Daher werden die Durchschnittswerte über das gesamte Resultset berechnet, wobei ein rangbezogener Rahmen gilt.

Die Begrenzung des Rahmens ist der Wert der Kosten für die Waren in der aktuellen Zeile plus zwei (z. B. die erste Zeile = 0,50 + 2,00). Zeilen sind für den Rahmen qualifiziert, wenn sie innerhalb dieses Zwei-Dollar-Bereichs liegen.

SELECT menu_category, menu_cogs_usd,
    AVG(menu_cogs_usd)
      OVER(ORDER BY menu_cogs_usd RANGE BETWEEN CURRENT ROW AND 2 FOLLOWING) avg_cogs
  FROM menu_items
  WHERE menu_category IN('Beverage','Dessert','Snack')
  GROUP BY menu_category, menu_cogs_usd
  ORDER BY menu_category, menu_cogs_usd;
Copy
+---------------+---------------+----------+
| MENU_CATEGORY | MENU_COGS_USD | AVG_COGS |
|---------------+---------------+----------|
| Beverage      |          0.50 |  1.18333 |
| Beverage      |          0.65 |  1.37857 |
| Beverage      |          0.75 |  1.50000 |
| Dessert       |          0.50 |  1.18333 |
| Dessert       |          1.00 |  1.87500 |
| Dessert       |          1.25 |  2.05000 |
| Dessert       |          2.50 |  3.16666 |
| Dessert       |          3.00 |  3.50000 |
| Snack         |          1.25 |  2.05000 |
| Snack         |          2.25 |  2.93750 |
| Snack         |          4.00 |  4.00000 |
+---------------+---------------+----------+

Der Wert avg_cogs für die erste Zeile ist zum Beispiel 1.1833. Dies wird berechnet als die Summe aller menu_cogs_usd-Werte, die zwischen 0,50 und 2,50 liegen, geteilt durch die Anzahl dieser Zeilen:

(0.50 + 0.65 + 0.75 + 0.50 + 1.00 + 1.25 + 2.50 + 1.25 + 2.25) / 9 = 1.18333

Die vorletzte Zeile hat einen avg_cogs-Wert von 2,93750. Dies wird berechnet als die Summe aller menu_cogs_usd-Werte, die zwischen 2,25 und 4,25 liegen, geteilt durch die Anzahl dieser Zeilen:

(2.25 + 2.50 + 3.00 + 4.00) / 4 = 2.93750

Die letzte Zeile ergibt 4,0 sowohl für avg_cogs als auch für menu_cogs_usd. Dieses Ergebnis ist genau, weil nur diese Zeile zu dem Rahmen gehört. 4.0 ist der Höchstwert von menu_cogs_usd im gesamten Ergebnis, sodass es sich um einen einzeiligen Rahmen handelt. Es hat keine „folgenden“ Zeilen.

Beachten Sie, dass diese Abfrage eine ORDER BY-Klausel für die Fensterfunktion und eine ORDER BY-Klausel für die Endergebnisse der Abfrage enthält. Die endgültige ORDER BY-Ausgabe hat keinen Einfluss auf die Berechnung der Ergebnisse der Fensterfunktion. Das geordnete Resultset zur Berechnung der Funktion ist ein Zwischen-Resultset, das in der endgültigen Abfrage nicht angezeigt wird.

Beispiele für RANGE BETWEEN mit NULL-Werten in der ORDER BY-Klausel

Die Tabelle nulls enthält fünf Zeilen und zwei davon haben NULL-Werte in der Spalte c1. Erstellen und laden Sie die Tabelle wie folgt:

CREATE OR REPLACE TABLE nulls(c1 int, c2 int);

INSERT INTO nulls VALUES
  (1,10),
  (2,20),
  (3,30),
  (NULL,20),
  (NULL,50);
Copy

Wenn NULLS LAST angegeben ist und der Fensterrahmen explizite Offsets verwendet, werden Zeilen mit NULL in c1 nur dann in den Rahmen aufgenommen, wenn der Wert ORDER BY der aktuellen Zeile NULL ist. Die folgende Abfrage gibt eine Summe von 50 zurück, wenn die Zeile 3 die aktuelle Zeile ist. Die folgende NULL-Zeile ist nicht im Rahmen enthalten.

SELECT c1 c1_nulls_last, c2,
    SUM(c2) OVER(ORDER BY c1 NULLS LAST RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING) sum_c2
  FROM nulls;
Copy
+---------------+----+--------+
| C1_NULLS_LAST | C2 | SUM_C2 |
|---------------+----+--------|
|             1 | 10 |     30 |
|             2 | 20 |     60 |
|             3 | 30 |     50 |
|          NULL | 20 |     70 |
|          NULL | 50 |     70 |
+---------------+----+--------+

Wenn NULLS LAST angegeben ist und der Fensterrahmen UNBOUNDED FOLLOWING verwendet, werden Zeilen mit NULL in c1 in den Rahmen aufgenommen. Die folgende Abfrage gibt eine Summe von 120 zurück, wenn die Zeile 3 die aktuelle Zeile ist. Die beiden folgenden NULL-Zeilen sind in dem Rahmen enthalten.

SELECT c1 c1_nulls_last, c2,
    SUM(c2) OVER(ORDER BY c1 NULLS LAST RANGE BETWEEN 1 PRECEDING AND UNBOUNDED FOLLOWING) sum_c2
  FROM nulls;
Copy
+---------------+----+--------+
| C1_NULLS_LAST | C2 | SUM_C2 |
|---------------+----+--------|
|             1 | 10 |    130 |
|             2 | 20 |    130 |
|             3 | 30 |    120 |
|          NULL | 20 |     70 |
|          NULL | 50 |     70 |
+---------------+----+--------+

Erstellen und laden Sie die Tabelle heavy_weather

Führen Sie dieses Skript aus, um Zeilen in der Tabelle heavy_weather zu erstellen und einzufügen, die in einigen Beispielen für Fensterfunktionen verwendet wird.

CREATE OR REPLACE TABLE heavy_weather
  (start_time TIMESTAMP, precip NUMBER(3,2), city VARCHAR(20), county VARCHAR(20));

INSERT INTO heavy_weather VALUES
('2021-12-23 06:56:00.000',0.08,'Mount Shasta','Siskiyou'),
('2021-12-23 07:51:00.000',0.09,'Mount Shasta','Siskiyou'),
('2021-12-23 16:23:00.000',0.56,'South Lake Tahoe','El Dorado'),
('2021-12-23 17:24:00.000',0.38,'South Lake Tahoe','El Dorado'),
('2021-12-23 18:30:00.000',0.28,'South Lake Tahoe','El Dorado'),
('2021-12-23 19:35:00.000',0.37,'Mammoth Lakes','Mono'),
('2021-12-23 19:36:00.000',0.80,'South Lake Tahoe','El Dorado'),
('2021-12-24 04:43:00.000',0.25,'Alta','Placer'),
('2021-12-24 05:26:00.000',0.34,'Alta','Placer'),
('2021-12-24 05:35:00.000',0.42,'Big Bear City','San Bernardino'),
('2021-12-24 06:49:00.000',0.17,'South Lake Tahoe','El Dorado'),
('2021-12-24 07:40:00.000',0.07,'Alta','Placer'),
('2021-12-24 08:36:00.000',0.07,'Alta','Placer'),
('2021-12-24 11:52:00.000',0.08,'Alta','Placer'),
('2021-12-24 12:52:00.000',0.38,'Alta','Placer'),
('2021-12-24 15:44:00.000',0.13,'Alta','Placer'),
('2021-12-24 15:53:00.000',0.07,'South Lake Tahoe','El Dorado'),
('2021-12-24 16:55:00.000',0.09,'Big Bear City','San Bernardino'),
('2021-12-24 21:53:00.000',0.07,'Montague','Siskiyou'),
('2021-12-25 02:52:00.000',0.07,'Alta','Placer'),
('2021-12-25 07:52:00.000',0.07,'Alta','Placer'),
('2021-12-25 08:52:00.000',0.08,'Alta','Placer'),
('2021-12-25 09:48:00.000',0.18,'Alta','Placer'),
('2021-12-25 12:52:00.000',0.10,'Alta','Placer'),
('2021-12-25 17:21:00.000',0.23,'Alturas','Modoc'),
('2021-12-25 17:52:00.000',1.54,'Alta','Placer'),
('2021-12-26 01:52:00.000',0.61,'Alta','Placer'),
('2021-12-26 05:43:00.000',0.16,'South Lake Tahoe','El Dorado'),
('2021-12-26 05:56:00.000',0.08,'Bishop','Inyo'),
('2021-12-26 06:52:00.000',0.75,'Bishop','Inyo'),
('2021-12-26 06:53:00.000',0.08,'Lebec','Los Angeles'),
('2021-12-26 07:52:00.000',0.65,'Alta','Placer'),
('2021-12-26 09:52:00.000',2.78,'Alta','Placer'),
('2021-12-26 09:55:00.000',0.07,'Big Bear City','San Bernardino'),
('2021-12-26 14:22:00.000',0.32,'Alta','Placer'),
('2021-12-26 14:52:00.000',0.34,'Alta','Placer'),
('2021-12-26 15:43:00.000',0.35,'Alta','Placer'),
('2021-12-26 17:31:00.000',5.24,'Alta','Placer'),
('2021-12-26 22:52:00.000',0.07,'Alta','Placer'),
('2021-12-26 23:15:00.000',0.52,'Alta','Placer'),
('2021-12-27 02:52:00.000',0.08,'Alta','Placer'),
('2021-12-27 03:52:00.000',0.14,'Alta','Placer'),
('2021-12-27 04:52:00.000',1.52,'Alta','Placer'),
('2021-12-27 14:37:00.000',0.89,'Alta','Placer'),
('2021-12-27 14:53:00.000',0.07,'South Lake Tahoe','El Dorado'),
('2021-12-27 17:53:00.000',0.07,'South Lake Tahoe','El Dorado'),
('2021-12-30 11:23:00.000',0.12,'Lebec','Los Angeles'),
('2021-12-30 11:43:00.000',0.98,'Lebec','Los Angeles'),
('2021-12-30 13:53:00.000',0.23,'Lebec','Los Angeles'),
('2021-12-30 14:53:00.000',0.13,'Lebec','Los Angeles'),
('2021-12-30 15:15:00.000',0.29,'Lebec','Los Angeles'),
('2021-12-30 17:53:00.000',0.10,'Lebec','Los Angeles'),
('2021-12-30 18:53:00.000',0.09,'Lebec','Los Angeles'),
('2021-12-30 19:53:00.000',0.07,'Lebec','Los Angeles'),
('2021-12-30 20:53:00.000',0.07,'Lebec','Los Angeles')
;
Copy