はじめに: 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 構文と比較できます。
一般的なクエリ ステートメントの実行シーケンスは次のとおりです。
- から
- どこ
- GROUP BY和集計関数
- 持っている
- 窓
- 資格を得る
- 明確な
- 注文方法
- リミット
通常、クエリ ステートメント内の 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を使用するとクエリ文がより簡潔で分かりやすくなります。
予防
-
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;