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

SQL Anywhere 11.0.1 (日本語) » SQL Anywhere サーバ - SQL の使用法 » データのクエリと変更 » OLAP のサポート » SQL Anywhere の Window 関数 » 基本集合関数

 

SUM 関数の例

次の例は、Window 関数として使用される SUM 関数を示したものです。クエリは、DepartmentID 別にデータを分割した結果セットを返し、在籍経験が長い人から順に従業員の給与の累積合計 (Sum_Salary) を算出します。結果セットには、カリフォルニア州、ユタ州、ニューヨーク州、またはアリゾナ州に住む従業員のみが含まれます。Sum_Salary のカラムは、従業員の給与の累積合計です。

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;

次のテーブルは、クエリからの結果セットを示します。結果セットは、DepartmentID ごとに分割されています。

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

DepartmentID 100 の場合、カリフォルニア州、ユタ州、ニューヨーク州、またはアリゾナ州に住む従業員の給与の累積合計は 434,091.69 ドルで、部門 200 の従業員の累積合計は 250,200.00 ドルです。

SUM 関数の正確な構文の詳細については、SUM 関数 [集合]を参照してください。

隣接ローのデルタの計算

2 つのウィンドウ (現在のローと直前のローのそれぞれに対するウィンドウ) を使用すると、隣接ローのデルタ (変化量) を計算できます。たとえば、次のクエリの結果では、ある従業員とその直前の従業員の給与のデルタ (Delta) を計算します。

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

CurrentRow ウィンドウでは、ウィンドウのサイズが ROWS BETWEEN CURRENT ROW AND CURRENT ROW に設定されているため、SUM は現在のローのみに対して実行されます。同様に、PreviousRow ウィンドウでは、ウィンドウのサイズが ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING に設定されているため、SUM は直前のローのみに対して実行されます。最初のローには先行するローがないため、このローの PreviousRow の値は NULL です。そのため Delta の値も NULL になります。

複雑な分析

次のクエリを考えてみます。このクエリは、データベース内で製品ごとに最上位の営業担当者 (総売り上げで定義) をリストします。

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;
グラフィカルなプラン

このクエリは、次の結果を返します。

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

元のクエリは、ProductID をサブクエリの相関外部参照として、ある製品の最高売り上げを判断する相関サブクエリを使用して作成されています。ただし、この場合のようにネストされたクエリを使用すると、コストの高いオプションになることがあります。これは、サブクエリに GROUP BY 句だけでなく、GROUP BY 句内の ORDER BY 句も含まれるからです。そのため、クエリ・オプティマイザは、同じセマンティックを保持したままになり、このネストされたクエリをジョインとして書き換えることができません。したがって、クエリの実行中は、外部ブロック内で計算される派生ローごとにサブクエリが評価されます。

ネストされたクエリを使用するコストがどの程度高くなるかを示すグラフィカルなプラン

グラフィカル・プランでコストの高い Filter 述部に注意してください。オプティマイザは、クエリの実行コストの 99% がこのプラン演算子に起因するものであると推定します。サブクエリのプランでは、メイン・ブロックのフィルタ演算子のコストが高くなる理由を明確にしています。サブクエリには、ネスト・ループ・ジョインが 2 つと、ハッシュ GROUP BY 演算が 1 つ、ソートが 1 つ含まれます。

ランキング関数を使用した書き換え

ランキング関数を使用した同じクエリの書き換えでは、同じ結果が非常に効率よく計算されます。

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;

この書き換えられたクエリは、プランがより単純になります。

ランキング関数により効率の良いプランを示すグラフィカルなプラン

GROUP BY 句が処理されてから select リスト項目の評価とクエリの ORDER BY 句の処理が行われるまでに、ウィンドウ演算子が計算されます。グラフィカルなプランでわかるように、3 つのテーブルのジョイン後、ジョインされたローは SalesRepresentative 属性と ProductID 属性の組み合わせでグループ化されます。したがって、total_quantity と total_sales の SUM 集合関数は、SalesRepresentative と ProductID の組み合わせごとに計算できます。

GROUP BY 句の評価に続いて、中間結果のローを total_sales の降順にランク付けするために、ウィンドウを使用して RANK 関数が計算されます。WINDOW 指定には PARTITION BY 句が含まれます。それによって、GROUP BY 句の結果が、今度は ProductID ごとに再分割 (再グループ化) されます。そのため、RANK 関数は、総売り上げの降順で製品ごとにローをランク付けしますが、その製品を販売した営業担当者はすべてまとめられます。このランキングにより、最上位の営業担当者を特定するのに必要なのは、ランクが 1 ではない派生テーブルのローを拒否するように派生テーブルの結果を制限するだけです。同順の場合 (結果セットのロー 7 と 8)、RANK は同じ値を返します。したがって、690 と 949 の両方の営業担当者が最終結果に出現します。

参照