MaxCompute の詳細 - エピソード 11 - 資格

はじめに:  MaxCompute は、ウィンドウ関数の結果をフィルタリングするための QUALIFY 構文をサポートしており、クエリ ステートメントをより簡潔で理解しやすくしています。ウィンドウ関数と QUALIFY 構文の関係は、集計関数 + GROUP BY 構文および HAVING 構文と比較できます。

MaxCompute(旧ODPS)は、Alibaba Cloudが独自に開発した業界トップクラスの分散型ビッグデータ処理プラットフォームで、グループ内で広く利用され、複数のBUの中核ビジネスを支えています。MaxCompute は、パフォーマンスを継続的に最適化することに加えて、ユーザー エクスペリエンスと SQL 言語の表現力を向上させ、MaxCompute 開発者の生産性を向上させることにも取り組んでいます。

MaxCompute は、MaxCompute2.0 の新世代 SQL エンジンに基づいており、SQL 言語のコンパイル プロセスの使いやすさと言語の表現力が大幅に向上しています。ここで、MaxCompute に関する詳細な一連の記事を開始します。

第 1 弾 -  MaxCompute コンパイラのエラーと警告を有効に活用する
第 2 弾 - 新しい基本データ型と組み込み関数
第 3 弾 - 複合型
第 4 弾 -  CTE、VALUES、SEMIJOIN
第 5 弾 -  SELECT TRANSFORM
第 6 弾- ユーザー定義型
7 番目 - グループ化セット、キューブ、ロールアップ
8 番目 - 動的型関数
9 番目 - スクリプト モードとパラメータ ビュー
10 番目 -  IF ELSE 分岐文

この記事では、MaxCompute がQUALIFY構文をサポートする方法を紹介します。QUALIFY 構文は、ウィンドウ (ウィンドウ) 関数の結果をフィルタするためのフィルタ条件の指定をサポートします。これは、集計関数や GROUP BY の後にデータを処理するための HAVING 構文に似ています。

QUALIFY機能の紹介

構文形式

QUALIFY [expression]

QUALIFY 構文は、ウィンドウ関数の結果をフィルターします。ウィンドウ関数と QUALIFY 構文の関係は、集計関数 + GROUP BY 構文および HAVING 構文と比較できます。
一般的なクエリ ステートメントの実行シーケンスは次のとおりです。

  1. から
  2. どこ
  3. GROUP BY和集計関数
  4. 持っている
  5. 資格を得る
  6. 明確な
  7. 注文方法
  8. リミット

通常、クエリ ステートメント内の QUALIFY 構文の実行順序は、ウィンドウ関数によって処理されるデータをフィルター処理するために使用されるWINDOW関数の後にあります。

使用するシーン

Window 関数の結果はフィルター処理する必要があります。QUALIFY 構文が登場する前は、SubQuery は一般的に FROM ステートメントで使用され、WHERE 条件によってフィルター処理されていました。次のように:

SELECT col1, col2
FROM
(
SELECT
t.a as col1,
sum(t.a) over (partition by t.b) as col2
FROM values (1, 2),(2,3),(2,2),(1,3),(4,2) t(a, b)
)
WHERE col2 > 4;

書き換えられたクエリステートメント:

SELECT 
t.a as col1, 
sum(t.a) over (partition by t.b) as col2 
FROM values (1, 2),(2,3),(2,2),(1,3),(4,2)  t(a, b) 
QUALIFY col2 > 4;

エイリアスを使用せずに、ウィンドウ関数を直接フィルターすることもできます。

SELECT t.a as col1,
sum(t.a) over (partition by t.b) as col2
FROM values (1, 2),(2,3),(2,2),(1,3),(4,2) t(a, b)
QUALIFY sum(t.a) over (partition by t.b)  > 4;

QUALIFY と WHERE/HAVING は同じように使用されますが、実行順序が異なるため、ユーザーは QUALIFY 構文を使用して次のような複雑な条件を記述することができます。

SELECT *
FROM values (1, 2) t(a, b)
QUALIFY sum(t.a) over (partition by t.b)  IN (SELECT a FROM t1)

QUALIFY は、ウィンドウ関数が有効になった後に実行されます。次のより複雑な例では、QUALIFY 構文の実行シーケンスを直感的に理解できます。

SELECT a, b, max(c)
FROM values (1, 2, 3),(1, 2, 4),(1, 3, 5),(2, 3, 6),(2, 4, 7),(3, 4, 8) t(a, b, c)
WHERE a < 3
GROUP BY a, b
HAVING max(c) > 5
QUALIFY sum(b) over (partition by a) > 3; 
--+------------+------------+------------+
--| a          | b          | _c2        |
--+------------+------------+------------+
--| 2          | 3          | 6          |
--| 2          | 4          | 7          |
--+------------+------------+------------+

row_number ウィンドウ関数の例では、すべての従業員を部門 (deptno) に従って (ウィンドウ列として) グループ化し、各グループを給与 (sal) に従って降順にソートし、自分のグループ内の従業員のシリアル番号を取得します。各部門の給与をクエリする必要があります。上位 3 つの情報は次のように実装されます。

  • データの準備

    create table if not exists emp
     (empno string,
      ename string,
      job string,
      mgr string,
      hiredate string,
      sal string,
      comm string,
      deptno string);
    
    insert into table emp values
    ('7369','SMITH','CLERK','7902','1980-12-17 00:00:00','800','','20')
    ,('7499','ALLEN','SALESMAN','7698','1981-02-20 00:00:00','1600','300','30')
    ,('7521','WARD','SALESMAN','7698','1981-02-22 00:00:00','1250','500','30')
    ,('7566','JONES','MANAGER','7839','1981-04-02 00:00:00','2975','','20')
    ,('7654','MARTIN','SALESMAN','7698','1981-09-28 00:00:00','1250','1400','30')
    ,('7698','BLAKE','MANAGER','7839','1981-05-01 00:00:00','2850','','30')
    ,('7782','CLARK','MANAGER','7839','1981-06-09 00:00:00','2450','','10')
    ,('7788','SCOTT','ANALYST','7566','1987-04-19 00:00:00','3000','','20')
    ,('7839','KING','PRESIDENT','','1981-11-17 00:00:00','5000','','10')
    ,('7844','TURNER','SALESMAN','7698','1981-09-08 00:00:00','1500','0','30')
    ,('7876','ADAMS','CLERK','7788','1987-05-23 00:00:00','1100','','20')
    ,('7900','JAMES','CLERK','7698','1981-12-03 00:00:00','950','','30')
    ,('7902','FORD','ANALYST','7566','1981-12-03 00:00:00','3000','','20')
    ,('7934','MILLER','CLERK','7782','1982-01-23 00:00:00','1300','','10')
    ,('7948','JACCKA','CLERK','7782','1981-04-12 00:00:00','5000','','10')
    ,('7956','WELAN','CLERK','7649','1982-07-20 00:00:00','2450','','10')
    ,('7956','TEBAGE','CLERK','7748','1982-12-30 00:00:00','1300','','10')
    ;
    
  • 次のように、FROM ステートメントで SubQuery を使用し、WHERE 条件によるフィルタリングを実装します。

    SELECT  a.*
    FROM    (
              SELECT  deptno
                      ,ename
                      ,sal
                      ,ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY sal DESC ) AS nums
              FROM    emp
          ) a
    WHERE a.nums<=3
    ;
    
  • 次のように QUALIFY を通じて実装されます。

    SELECT  deptno
          ,ename
          ,sal
          ,ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY sal DESC ) AS nums
    FROM    emp
    QUALIFY nums <= 3
    ;
    

結果は以下のようになりますが、QUALIFYを使用するとクエリ文がより簡潔で分かりやすくなります。
画像.png

予防

  • QUALIFY 構文では、クエリ ステートメントに少なくとも 1 つのウィンドウ関数が必要です。ウィンドウ関数がない場合、QUALIFY 構文を使用するとエラーが報告されますFAILED: ODPS-0130071:[3,1] Semantic analysis exception - use QUALIFY clause without window functionエラーの例は以下のとおりです。

    SELECT * 
    FROM values (1, 2) t(a, b) 
    QUALIFY a > 1;
    
  • QUALIFY 構文を使用すると、フィルター条件の一部として SELECT で列の別名を使用できます。例は次のとおりです。

    SELECT 
    sum(t.a) over (partition by t.b) as c1 
    FROM values (1, 2) t(a, b) 
    QUALIFY c1 > 1;
    

おすすめ

転載: blog.csdn.net/weixin_48534929/article/details/132603218