Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 11.0.1 (Deutsch) » SQL Anywhere Server - SQL-Benutzerhandbuch » Daten abfragen und ändern » OLAP-Unterstützung » Fensterfunktionen in SQL Anywhere » Basis-Aggregatfunktionen

 

Beispiel für SUM-Funktion

Im folgenden Beispiel wird die SUM-Funktion als eine Fensterfunktion verwendet. Die Abfrage gibt eine Ergebnismenge zurück, die die Daten nach "DepartmentID" partitioniert und dann eine kumulative Summe der Gehälter beginnend mit dem am längsten im Unternehmen beschäftigten Mitarbeiter anzeigt. Die Ergebnismenge enthält nur die Mitarbeiter, die in Kalifornien, Utah, New York oder Arizona leben. Die Spalte "Sum_Salary" liefert die kumulative Gesamtsumme der Mitarbeitergehälter.

SELECT DepartmentID, Surname, StartDate, Salary,
SUM( Salary ) OVER ( PARTITION BY DepartmentID
    ORDER BY StartDate
    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) 
AS "Sum_Salary"
FROM Employees
WHERE State IN ( 'CA', 'UT', 'NY', 'AZ' ) 
   AND DepartmentID IN ( '100', '200' )
ORDER BY DepartmentID, StartDate;

Die nachstehende Tabelle stellt die Ergebnismenge dieser Abfrage dar. Die Ergebnismenge wird nach "DepartmentID" partitioniert.

DepartmentID Surname StartDate Salary Sum_Salary
1 100 Whitney 1984-08-28 45700.00 45700.00
2 100 Cobb 1985-01-01 62000.00 107700.00
3 100 Shishov 1986-06-07 72995.00 180695.00
4 100 Driscoll 1986-07-01 48023.69 228718.69
5 100 Guevara 1986-10-14 42998.00 271716.69
6 100 Wang 1988-09-29 68400.00 340116.69
7 100 Soo 1990-07-31 39075.00 379191.69
8 100 Diaz 1990-08-19 54900.00 434091.69
9 200 Overbey 1987-02-19 39300.00 39300.00
10 200 Martel 1989-10-16 55700.00 95000.00
11 200 Savarino 1989-11-07 72300.00 167300.00
12 200 Clark 1990-07-21 45000.00 212300.00
13 200 Goggin 1990-08-05 37900.00 250200.00

Für die DepartmentID 100 ist die kumulative Gesamtsumme der Gehälter von Mitarbeitern in Kalifornien, Utah, New York und Arizona insgesamt $434,091.69 und die kumulative Gesamtsumme für die Mitarbeiter in DepartmentID 200 beträgt $250,200.00.

Weitere Hinweise zur genauen Syntax der SUM-Funktion finden Sie unter SUM-Funktion [Aggregat].

Deltawerte zwischen angrenzenden Zeilen berechnen

Durch die Verwendung von zwei Fenstern - ein Fenster für die aktuelle Zeile, das andere für die nächste Zeile - können Sie Deltawerte bzw. Unterschiede zwischen zwei angrenzenden Zeilen berechnen. Die folgende Abfrage berechnet beispielsweise den Deltawert (Delta) zwischen den Gehältern eines Mitarbeiters und des nächsten Mitarbeiters in den Ergebnissen:

SELECT EmployeeID AS EmployeeNumber, 
   Surname AS LastName,
   SUM( Salary ) OVER ( ORDER BY BirthDate 
      ROWS BETWEEN CURRENT ROW AND CURRENT ROW ) 
      AS CurrentRow,
   SUM( Salary ) OVER ( ORDER BY BirthDate
      ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING ) 
      AS PreviousRow,
   ( CurrentRow - PreviousRow ) AS Delta
FROM Employees
WHERE State IN ( 'NY' );
EmployeeNumber LastName CurrentRow PreviousRow Delta
1 913 Martel 55700.000 (NULL) (NULL)
2 1062 Blaikie 54900.000 55700.000 -800.000
3 249 Guevara 42998.000 54900.000 -11902.000
4 390 Davidson 57090.000 42998.000 14092.000
5 102 Whitney 45700.000 57090.000 -11390.000
6 1507 Wetherby 35745.000 45700.000 -9955.000
7 1751 Ahmed 34992.000 35745.000 -753.000
8 1157 Soo 39075.000 34992.000 4083.000

Beachten Sie, dass SUM nur auf die aktuelle Zeile für das CurrentRow-Fenster angewendet wird, da die Fenstergröße auf ROWS BETWEEN CURRENT ROW AND CURRENT ROW eingestellt wurde. Ebenso wird SUM nur auf die vorherige Zeile für das PreviousRow-Fenster angewendet, da die Fenstergröße auf ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING eingestellt wurde. Der Wert von PreviousRow in der ersten Zeile ist NULL, da es keine vorherige Zeile gibt und somit auch der Deltawert NULL beträgt.

Komplexe Analysen

In der folgenden Abfrage werden die Spitzenverkäufer (definiert nach Gesamtumsatz) für die einzelnen Produkte in der Datenbank aufgeführt:

SELECT s.ProductID AS Products, o.SalesRepresentative, 
     SUM( s.Quantity ) AS total_quantity,
     SUM( s.Quantity * p.UnitPrice ) AS total_sales
  FROM SalesOrders o KEY JOIN SalesOrderItems s 
    KEY JOIN Products p
  GROUP BY s.ProductID, o.SalesRepresentative
  HAVING total_sales = ( 
    SELECT First SUM( s2.Quantity * p2.UnitPrice ) 
        AS sum_sales
      FROM SalesOrders o2 KEY JOIN
        SalesOrderItems s2 KEY JOIN Products p2
      WHERE s2.ProductID = s.ProductID
      GROUP BY o2.SalesRepresentative
      ORDER BY sum_sales DESC )
  ORDER BY s.ProductID;
Grafischer Plan

Diese Abfrage liefert das folgende Ergebnis:

Products SalesRepresentative total_quantity total_sales
1 300 299 660 5940.00
2 301 299 516 7224.00
3 302 299 336 4704.00
4 400 299 458 4122.00
5 401 902 360 3600.00
6 500 949 360 2520.00
7 501 690 360 2520.00
8 501 949 360 2520.00
9 600 299 612 14688.00
10 601 299 636 15264.00
11 700 299 1008 15120.00

Die ursprüngliche Abfrage wird durch eine korrelierte Unterabfrage gebildet, welche die höchsten Verkäufe für jedes einzelne Produkt ermittelt, da "ProductID" die korrelierte äußere Referenz der Unterabfrage ist. Wie auch in diesem Fall ist eine verschachtelte Abfrage jedoch oft eine kostenträchtige Option. Dies liegt daran, dass die Unterabfrage nicht nur eine GROUP BY-Klausel umfasst, sondern innerhalb dieser auch eine ORDER BY-Klausel. Dies macht es dem Abfrageoptimierer unmöglich, die verschachtelte Abfrage zu einem Join umzuschreiben und dabei die gleiche Semantik beizubehalten. Daher wird die Unterabfrage während der Abfrageausführung für jede abgeleitete Zeile ausgewertet, die im äußeren Block berechnet wird.

Grafischer Plan, der anzeigt, wie kostenträchtig die Verwendung von verschachtelten Abfragen ist

Beachten Sie das kostenträchtige Filterprädikat im grafischen Plan: Der Optimierer schätzt, dass 99 % der Ausführungskosten der Abfrage auf diesen Plan-Operator zurückzuführen sind. Der Plan für die Unterabfrage zeigt deutlich, warum der Filter-Operator im Hauptblock so kostenträchtig ist: Die Unterabfrage enthält zwei Nested Loops Joins, einen Hash-basierten GROUP BY-Vorgang und einen Sortiervorgang.

Umschreiben mit einer Rangfunktion

Ein Umschreiben der gleichen Abfrage mithilfe einer Rangfunktion berechnet das identische Ergebnis viel effizienter:

SELECT v.ProductID, v.SalesRepresentative, 
  v.total_quantity, v.total_sales
  FROM ( SELECT o.SalesRepresentative, s.ProductID,
            SUM( s.Quantity ) AS total_quantity,
            SUM( s.Quantity * p.UnitPrice ) AS total_sales,
            RANK() OVER ( PARTITION BY s.ProductID 
              ORDER BY SUM( s.Quantity * p.UnitPrice ) DESC ) 
              AS sales_ranking
           FROM SalesOrders o KEY JOIN SalesOrderItems s KEY JOIN Products p
           GROUP BY o.SalesRepresentative, s.ProductID ) 
           AS v
  WHERE sales_ranking = 1
  ORDER BY v.ProductID;

Die umgeschriebene Abfrage ergibt einen einfacheren Plan:

Grafischer Plan, der einen effizienteren Plan dank der Rangfunktion anzeigt

Bedenken Sie, dass ein Fenster-Operator nach der Verarbeitung einer GROUP BY-Klausel und vor der Auswertung der Elemente der SELECT-Liste sowie der ORDER BY-Klausel der Abfrage berechnet wird. Wie im grafischen Plan zu erkennen ist, werden die verknüpften Zeilen nach der Verknüpfung der drei Tabellen durch die Kombination der Attribute "SalesRepresentative" und "ProductID" gruppiert. Daher können die SUM-Aggregatfunktionen "total_quantity" und "total_sales" für alle Kombinationen von "SalesRepresentative" und "ProductID" berechnet werden.

Nach der Auswertung der GROUP BY-Klausel wird die RANK-Funktion berechnet, um mithilfe eines Fensters die Rangfolge der Zeilen im Zwischenergebnis absteigend nach "total_sales" darzustellen. Beachten Sie, dass die WINDOW-Spezifikation eine PARTITION BY-Klausel umfasst. Dadurch wird das Ergebnis der GROUP BY-Klausel neu partitioniert (oder neu gruppiert) - dieses Mal nach "ProductID". Deshalb sortiert die RANK-Funktion die Zeilen für jedes Produkt absteigend nach "total_sales", jedoch nur für die Verkäufer, die dieses Produkt verkauft haben. Durch diese Rangfolge ist es zum Ermitteln der Spitzenverkäufer lediglich erforderlich, das Ergebnis der abgeleiteten Tabelle einzuschränken, um die Zeilen auszuschließen, in denen die Rangfolge nicht 1 ist. Bei gleichen Werten (Zeilen 7 und 8 in der Ergebnismenge), liefert RANK den gleichen Wert. Daher erscheinen die Verkäufer 690 und 949 beide im Endergebnis.

Siehe auch