MaxCompute では、SELECT 文を使用してデータをクエリできます。このトピックでは、MaxCompute における SELECT 文の構文について説明します。また、SELECT 文を使用して、ネストされたクエリ、ソート、グループによるクエリなどの操作を実行する方法についても説明します。
SELECT 文を実行する前に、デスティネーションテーブルに対する Select 権限が付与されていることを確認してください。詳細については、「MaxCompute の権限」をご参照ください。
次のプラットフォームでステートメントを実行できます:
概要
SELECT 文は、指定された条件を満たすデータをテーブルからクエリするために使用されます。次の表は、さまざまなシナリオで実行できるクエリ操作について説明しています。
クエリ操作 | 説明 |
クエリの結果に基づいてさらにクエリを実行できます。 | |
2 つのデータセットの共通部分、和集合、または補集合を取得できます。 | |
| |
右のテーブルを使用して左のテーブルのデータをフィルタリングし、左のテーブルにのみ表示されるデータを取得できます。 | |
1 つの大きなテーブルと 1 つ以上の小さなテーブルで | |
結合する 2 つのテーブルにホットキー値が含まれている場合、ロングテール問題が発生する可能性があります。2 つのテーブルからホットキー値を抽出し、ホットキー値の結合結果と非ホットキー値の結合結果を別々に計算してから、計算されたデータを結合できます。 | |
LATERAL VIEW をユーザー定義のテーブル値関数 (UDTF) と共に使用して、1 行のデータを複数行に分割できます。 | |
複数ディメンションのデータを集計および分析できます。 | |
| |
分割サイズを変更して、サブタスクの並列処理を制御できます。 | |
MaxCompute では、Delta テーブルに対してタイムトラベルクエリと増分クエリを実行できます。
|
制限
SELECT文が実行された後、最大 10,000 行の結果が表示されます。返される結果のサイズは 10 MB 未満である必要があります。この制限は、SELECT句には適用されません。SELECT句は、上位層からのクエリに応じてすべての結果を返します。SELECT文を実行してパーティションテーブルからデータをクエリする場合、テーブルで全表スキャンを実行することはできません。2018 年 1 月 10 日 20:00:00 以降にプロジェクトが作成された場合、プロジェクト内のパーティションテーブルで全表スキャンを実行することはできません。この制限は、SELECT 文を実行してテーブルからデータをクエリする場合に適用されます。パーティションテーブルからデータをクエリするには、スキャンするパーティションを指定する必要があります。これにより、不要な I/O が削減され、計算リソース が節約されます。また、従量課金 の課金方法を使用している場合、計算コストも削減されます。
パーティションテーブルで全表スキャンを実行するには、全表スキャンに使用する SQL 文の前に
SET odps.sql.allow.fullscan=true;コマンドを追加します。次に、追加されたコマンドを SQL 文と共にコミットして実行します。たとえば、sale_detailパーティションテーブルで全表スキャンを実行する場合は、次の文を実行します。SET odps.sql.allow.fullscan=true; SELECT * from sale_detail;クラスタ化テーブルをクエリする場合、単一テーブルでスキャンできるパーティションの数が 400 以下の場合にのみ、SELECT 文を実行してバケットプルーニングを実行できます。バケットプルーニングが有効にならない場合、スキャンされるデータレコードの数が増加します。従量課金 の課金方法を使用していて、バケットプルーニングが有効にならない場合、コストが増加します。サブスクリプション の課金方法を使用していて、バケットプルーニングが有効にならない場合、SQL 計算のパフォーマンスが低下します。
構文
[WITH <cte>[, ...] ]
SELECT [ALL | DISTINCT] <SELECT_expr>[, <EXCEPT_expr>][, <REPLACE_expr>] ...
FROM <TABLE_reference>
[WHERE <WHERE_condition>]
[GROUP BY {<col_list>|ROLLUP(<col_list>)}]
[HAVING <HAVING_condition>]
[WINDOW <WINDOW_clause>]
[ORDER BY <ORDER_condition>]
[DISTRIBUTE BY <DISTRIBUTE_condition> [SORT BY <SORT_condition>]|[ CLUSTER BY <CLUSTER_condition>] ]
[LIMIT <number>]SELECT 文の句を実行する順序の詳細については、「SELECT 文の句の実行順序」をご参照ください。
サンプルデータ
このトピックでは、サンプルのソースデータとサンプルのステートメントを提供して、ソースデータを準備する方法を示します。次のサンプルステートメントは、sale_detail テーブルを作成し、このテーブルにデータを挿入する方法を示しています。
-- sale_detail という名前のパーティションテーブルを作成します。
CREATE TABLE IF NOT EXISTS sale_detail
(
shop_name STRING,
customer_id STRING,
total_price DOUBLE
)
PARTITIONED BY (sale_date STRING, region STRING);
-- sale_detail テーブルにパーティションを追加します。
ALTER TABLE sale_detail ADD PARTITION (sale_date='2013', region='china');
-- sale_detail テーブルにデータを挿入します。
INSERT INTO sale_detail PARTITION (sale_date='2013', region='china') VALUES ('s1','c1',100.1),('s2','c2',100.2),('s3','c3',100.3);sale_detail テーブルのデータをクエリします。サンプルステートメント:
SELECT * FROM sale_detail;
-- 次の結果が返されます。
+------------+-------------+-------------+------------+------------+
| shop_name | customer_id | total_price | sale_date | region |
+------------+-------------+-------------+------------+------------+
| s1 | c1 | 100.1 | 2013 | china |
| s2 | c2 | 100.2 | 2013 | china |
| s3 | c3 | 100.3 | 2013 | china |
+------------+-------------+-------------+------------+------------+WITH 句 (CTE)
WITH 句はオプションです。WITH 句には、1 つ以上の共通テーブル式 (CTE) が含まれています。CTE は、ランタイム環境で一時テーブルとして使用されます。後続のクエリで一時テーブルを参照できます。CTE を使用する場合、次のルールに従う必要があります。
CTE の名前は、WITH 句内で一意である必要があります。
WITH 句で定義された CTE は、同じ WITH 句で定義された他の CTE のみによって参照できます。
たとえば、A は WITH 句の最初の CTE、B は同じ WITH 句の 2 番目の CTE です。
A が A を参照する場合、参照は無効です。CTE の誤った使用法:
WITH A AS (SELECT 1 FROM A) SELECT * FROM A;次の結果が返されます。
FAILED: ODPS-0130161:[1,6] Parse exception - recursive cte A is invalid, it must have an initial_part and a recursive_part, which must be connected by UNION ALLA が B を参照し、B が A を参照する場合、参照は無効です。循環参照はサポートされていません。CTE の誤った使用法:
WITH A AS (SELECT * FROM B ), B AS (SELECT * FROM A ) SELECT * FROM B;次の結果が返されます。
FAILED: ODPS-0130071:[1,26] Semantic analysis exception - while resolving view B - [1,51]recursive function call is not supported, cycle is A->B->A
正しい使用法のサンプルステートメント:
WITH
A AS (SELECT 1 AS C),
B AS (SELECT * FROM A)
SELECT * FROM B;次の結果が返されます。
+---+
| c |
+---+
| 1 |
+---+列式 (SELECT_expr)
select_expr は必須です。SELECT_expr は、col1_name, col2_name, 列式,... の形式です。この形式は、クエリする共通列またはパーティションキー列、あるいはデータのクエリに使用する正規表現 を示します。select_expr を使用する場合、次のルールに従う必要があります。
データを読み取る列の名前を指定します。
次のステートメントは、
sale_detailテーブルからshop_name列のデータを読み取ります。サンプルステートメント:SELECT shop_name FROM sale_detail;次の結果が返されます。
+------------+ | shop_name | +------------+ | s1 | | s2 | | s3 | +------------+アスタリスク (
*) を使用してすべての列を表します。また、アスタリスク (*) を WHERE 句と共に使用して、フィルタ条件を指定することもできます。次のステートメントは、
sale_detailテーブルからすべての列のデータをクエリします。サンプルステートメント:-- 現在のセッションに対してのみ全表スキャンを有効にします。 SET odps.sql.allow.fullscan=true; SELECT * FROM sale_detail;次の結果が返されます。
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ | s1 | c1 | 100.1 | 2013 | china | | s2 | c2 | 100.2 | 2013 | china | | s3 | c3 | 100.3 | 2013 | china | +------------+-------------+-------------+------------+------------+次のステートメントは、アスタリスク (*) を WHERE と共に使用して、フィルタ条件を指定します。サンプルステートメント:
SELECT * FROM sale_detail WHERE shop_name='s1';次の結果が返されます。
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ | s1 | c1 | 100.1 | 2013 | china | +------------+-------------+-------------+------------+------------+
正規表現 を使用します。
次のステートメントは、
sale_detailテーブルから、名前がshで始まるすべての列のデータをクエリします。サンプルステートメント:SELECT `sh.*` FROM sale_detail;次の結果が返されます。
+------------+ | shop_name | +------------+ | s1 | | s2 | | s3 | +------------+次のステートメントは、
sale_detailテーブルから、名前がshop_nameでないすべての列のデータをクエリします。サンプルステートメント:SELECT `(shop_name)?+.+` FROM sale_detail;次の結果が返されます。
+-------------+-------------+------------+------------+ | customer_id | total_price | sale_date | region | +-------------+-------------+------------+------------+ | c1 | 100.1 | 2013 | china | | c2 | 100.2 | 2013 | china | | c3 | 100.3 | 2013 | china | +-------------+-------------+------------+------------+次のステートメントは、
sale_detailテーブルから、名前がshop_nameおよびcustomer_idでないすべての列のデータをクエリします。サンプルステートメント:SELECT `(shop_name|customer_id)?+.+` FROM sale_detail;次の結果が返されます。
+-------------+------------+------------+ | total_price | sale_date | region | +-------------+------------+------------+ | 100.1 | 2013 | china | | 100.2 | 2013 | china | | 100.3 | 2013 | china | +-------------+------------+------------+次のステートメントは、
sale_detailテーブルから、名前がtで始まらないすべての列のデータをクエリします。サンプルステートメント:SELECT `(t.*)?+.+` FROM sale_detail;次の結果が返されます。
+------------+-------------+------------+------------+ | shop_name | customer_id | sale_date | region | +------------+-------------+------------+------------+ | s1 | c1 | 2013 | china | | s2 | c2 | 2013 | china | | s3 | c3 | 2013 | china | +------------+-------------+------------+------------+説明col2 の名前が col1 の名前のプレフィックスであり、複数の列を除外する場合、col1 の名前が col2 の名前の前に配置されていることを確認する必要があります。長い列名は短い列名の前に配置されます。たとえば、パーティションテーブルの 2 つのパーティションをクエリする必要はありません。1 つのパーティションの名前は
ds、もう 1 つのパーティションの名前はdshhです。ds パーティションの名前は、dshh パーティションの名前のプレフィックスです。したがって、SELECT `(dshhds)?+.+` FROM t;式は正しいですが、SELECT `(dsdshh)?+.+` FROM t;式は正しくありません。
列名の前に
DISTINCTを使用して、列から重複値を除外し、個別の値のみを返します。列名の前にALLを使用すると、重複値を含む列のすべての値が返されます。DISTINCT が使用されていない場合、ALLが使用されます。次のステートメントは、sale_detail テーブルから region 列のデータをクエリし、1 つの個別の値のみを返します。サンプルステートメント:
SELECT DISTINCT region FROM sale_detail;次の結果が返されます。
+------------+ | region | +------------+ | china | +------------+次のステートメントは、
DISTINCTオプションの後に複数の列を指定します。DISTINCTオプションは、単一の列ではなく、指定されたすべての列に有効になります。サンプルステートメント:SELECT DISTINCT region, sale_date FROM sale_detail;次の結果が返されます。
+------------+------------+ | region | sale_date | +------------+------------+ | china | 2013 | +------------+------------+次のステートメントでは、DISTINCT がウィンドウ関数と共に使用されています。DISTINCT は、ウィンドウ関数の計算結果の重複を削除するために使用されます。サンプルステートメント:
SET odps.sql.allow.fullscan=true; SELECT DISTINCT sale_date, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY total_price) AS rn FROM sale_detail;次の結果が返されます。
+-----------+------------+ | sale_date | rn | +-----------+------------+ | 2013 | 1 | +-----------+------------+次のステートメントでは、DISTINCT を GROUP BY と共に使用することはできません。たとえば、次のステートメントを実行すると、エラーが返されます。
SELECT DISTINCT shop_name FROM sale_detail GROUP BY shop_name; -- エラーメッセージ「GROUP BY cannot be used with SELECT DISTINCT」が返されます。
列除外式 (EXCEPT_expr)
except_expr はオプションです。EXCEPT_expr は、EXCEPT(col1_name, col2_name, ...) 形式です。except_expr を使用すると、テーブルのほとんどの列からデータを読み取り、テーブルの少数の列からデータを除外できます。たとえば、SELECT * EXCEPT(col1_name, col2_name, ...) FROM ...; 文を実行して、col1 列と col2 列を除くすべての列からデータを読み取ることができます。
サンプルステートメント:
-- sale_detail テーブルの region 列を除くすべての列からデータを読み取ります。
SELECT * EXCEPT(region) FROM sale_detail;次の結果が返されます。
+-----------+-------------+-------------+-----------+
| shop_name | customer_id | total_price | sale_date |
+-----------+-------------+-------------+-----------+
| s1 | c1 | 100.1 | 2013 |
| s2 | c2 | 100.2 | 2013 |
| s3 | c3 | 100.3 | 2013 |
+-----------+-------------+-------------+-----------+列変更式 (REPLACE_expr)
replace_expr はオプションです。REPLACE_expr は、REPLACE(exp1 [as] col1_name, exp2 [as] col2_name, ...) 形式です。replace_expr を使用すると、テーブルのほとんどの列からデータを読み取り、テーブルの少数の列のデータを変更できます。たとえば、SELECT * REPLACE(exp1 as col1_name, exp2 as col2_name, ...) FROM ...; 文を実行して、テーブルからデータを読み取るときに、col1 列のデータを exp1 の計算結果に置き換え、col2 列のデータを exp2 の計算結果に置き換えることができます。
サンプルステートメント:
-- sale_detail テーブルからデータを読み取り、total_price 列と region 列のデータを変更します。
SELECT * REPLACE(total_price+100 AS total_price, 'shanghai' AS region) FROM sale_detail;次の結果が返されます。
+-----------+-------------+-------------+-----------+--------+
| shop_name | customer_id | total_price | sale_date | region |
+-----------+-------------+-------------+-----------+--------+
| s1 | c1 | 200.1 | 2013 | shanghai |
| s2 | c2 | 200.2 | 2013 | shanghai |
| s3 | c3 | 200.3 | 2013 | shanghai |
+-----------+-------------+-------------+-----------+--------+デスティネーションテーブル情報 (TABLE_reference)
table_reference は必須です。TABLE_reference は、クエリするテーブルを指定します。table_reference を使用する場合、次のルールに従う必要があります。
デスティネーションテーブルの名前を指定します。サンプルステートメント:
SELECT customer_id FROM sale_detail;次の結果が返されます。
+-------------+ | customer_id | +-------------+ | c1 | | c2 | | c3 | +-------------+ネストされたサブクエリを使用します。サンプルステートメント:
SELECT * FROM (SELECT region,sale_date FROM sale_detail) t WHERE region = 'china';次の結果が返されます。
+------------+------------+ | region | sale_date | +------------+------------+ | china | 2013 | | china | 2013 | | china | 2013 | +------------+------------+
WHERE 句 (WHERE_condition)
where_condition はオプションです。WHERE 句はフィルタ条件を指定します。where_condition がパーティションテーブルに使用される場合、列プルーニングを実行できます。where_condition を使用する場合、次のルールに従う必要があります。
where_condition を関係演算子 と共に使用して、指定された条件を満たすデータを取得します。関係演算子 には次のものがあります。
>、<、=、>=、<=、および<>LIKEおよびRLIKEIN、NOT INBETWEEN…AND
詳細については、「関係演算子」をご参照ください。
次のステートメントは、
where_conditionでスキャンするパーティションを指定します。これにより、全表スキャンが回避されます。サンプルステートメント:SELECT * FROM sale_detail WHERE sale_date >= '2008' AND sale_date <= '2014'; -- 前のステートメントは、次のステートメントと同じです。 SELECT * FROM sale_detail WHERE sale_date BETWEEN '2008' AND '2014';次の結果が返されます。
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ | s1 | c1 | 100.1 | 2013 | china | | s2 | c2 | 100.2 | 2013 | china | | s3 | c3 | 100.3 | 2013 | china | +------------+-------------+-------------+------------+------------+説明EXPLAIN 文を実行して、パーティションプルーニングが有効になっているかどうかを確認できます。一般的なユーザー定義関数 (UDF) または JOIN のパーティション条件設定により、パーティションプルーニングが失敗する可能性があります。詳細については、「パーティションプルーニングが有効かどうかを確認する」をご参照ください。
UDF ベースのパーティションプルーニングを使用します。UDF を使用する場合、MaxCompute は UDF を小さなジョブとして実行し、これらのジョブの結果でパーティションをバックフィルします。
実装方法
UDF を作成するときに、UDF クラスにアノテーションを追加します。
@com.aliyun.odps.udf.annotation.UdfProperty(isDeterministic=true)説明UDF アノテーション
com.aliyun.odps.udf.annotation.UdfPropertyは、odps-sdk-udf.jar ファイルで定義されています。このアノテーションを使用するには、参照される odps-sdk-udf のバージョンを 0.30.X 以降に更新する必要があります。実行する SQL 文の前に
SET odps.sql.udf.ppr.deterministic = true;を追加します。その後、SQL 文のすべての UDF はdeterministicUDF と見なされます。前の SET コマンドは、ジョブの結果でパーティションをバックフィルします。最大 1,000 個のパーティションをジョブの結果でバックフィルできます。UDF クラスにアノテーションを追加すると、1,000 個を超えるパーティションがバックフィルされていることを示すエラーが返される場合があります。このエラーを無視するには、SET odps.sql.udf.ppr.to.subquery = false;コマンドを実行します。このコマンドを実行した後、UDF ベースのパーティションプルーニングは有効になりません。
注意事項
UDF を使用してパーティションプルーニングを実行する場合、UDF はテーブルのクエリに使用する
WHERE句に配置する必要があります。UDF ベースのパーティションプルーニングは、UDF を WHERE 句に配置した場合にのみ有効になります。正しい使用法のサンプルステートメント:
-- ソーステーブルのクエリに使用する WHERE 句に UDF を配置します。 SELECT key, value FROM srcp WHERE udf(ds) = 'xx';誤った使用法のサンプルステートメント:
-- JOIN 句の ON 条件の後に UDF を配置します。UDF ベースのパーティションプルーニングは有効になりません。 SELECT A.c1, A.c2 FROM srcp1 A JOIN srcp2 B ON A.c1 = B.c1 AND udf(A.ds) ='xx';
列式 (SELECT_expr) で、列エイリアスという名前が変更された列が関数を使用している場合、
WHERE句で列エイリアスを参照することはできません。誤ったサンプルステートメント:SELECT task_name ,inst_id ,settings ,GET_JSON_OBJECT(settings, '$.SKYNET_ID') AS skynet_id ,GET_JSON_OBJECT(settings, '$.SKYNET_NODENAME') AS user_agent FROM Information_Schema.TASKS_HISTORY WHERE ds = '20211215' AND skynet_id IS NOT NULL LIMIT 10;
GROUP BY (col_list)
GROUP BY はオプションです。ほとんどの場合、GROUP BY は 集計関数 と共に使用され、指定された共通列、パーティションキー列、または正規表現 に基づいて列をグループ化します。GROUP BY を使用する場合、次のルールに従う必要があります。
GROUP BYはSELECTよりも優先されます。したがって、GROUP BYの列は、SELECTの入力テーブルの列名、または SELECT の入力テーブルの列によって形成される式で指定できます。GROUP BY を使用する場合、次の点に注意してください。GROUP BYの列が正規表現 で指定されている場合、完全な式を使用する必要があります。SELECT文で集計関数を使用しない列は、GROUP BYで指定する必要があります。
例:
次のステートメントは、列名 region によってテーブルデータをグループ化します。この場合、データは region 列の値に基づいてグループ化されます。サンプルステートメント:
SELECT region FROM sale_detail GROUP BY region;次の結果が返されます。
+------------+ | region | +------------+ | china | +------------+次のステートメントは、region 列の値に基づいてテーブルデータをグループ化し、各グループの合計売上高を返します。サンプルステートメント:
SELECT SUM(total_price) FROM sale_detail GROUP BY region;次の結果が返されます。
+------------+ | _c0 | +------------+ | 300.6 | +------------+次のステートメントは、region 列の値に基づいてテーブルデータをグループ化し、各グループの個別の値と合計売上高を返します。サンプルステートメント:
SELECT region, SUM (total_price) FROM sale_detail GROUP BY region;次の結果が返されます。
+------------+------------+ | region | _c1 | +------------+------------+ | china | 300.6 | +------------+------------+次のステートメントは、
SELECT文の出力列のエイリアスに基づいてテーブルデータをグループ化します。サンプルステートメント:SELECT region AS r FROM sale_detail GROUP BY r; -- 前のステートメントは、次のステートメントと同じです。 SELECT region AS r FROM sale_detail GROUP BY region;次の結果が返されます。
+------------+ | r | +------------+ | china | +------------+次のステートメントは、列式に基づいてテーブルデータをグループ化します。サンプルステートメント:
SELECT 2 + total_price AS r FROM sale_detail GROUP BY 2 + total_price;次の結果返されます。
+------------+ | r | +------------+ | 102.1 | | 102.2 | | 102.3 | +------------+SELECT文の一部の列が集計関数を使用していない場合、これらの列はGROUP BYで指定する必要があります。そうでない場合、エラーが返されます。誤った使用法のサンプルステートメント:SELECT region, total_price FROM sale_detail GROUP BY region;正しい使用法のサンプルステートメント:
SELECT region, total_price FROM sale_detail GROUP BY region, total_price;次の結果が返されます。
+------------+-------------+ | region | total_price | +------------+-------------+ | china | 100.1 | | china | 100.2 | | china | 100.3 | +------------+-------------+
SELECT 文の前に
SET hive.groupby.position.alias=true;コマンドを追加すると、GROUP BY句の整数定数は、SELECT文の列番号と見なされます。サンプルステートメント:-- このコマンドを次の SELECT 文と共に実行します。 SET odps.sql.groupby.position.alias=true; -- 1 は region 列を示し、これは次の SELECT 文によって読み取られる最初の列です。このステートメントは、region 列の値に基づいてテーブルデータをグループ化し、region 列の個別の値と各グループの合計売上高を返します。 SELECT region, SUM(total_price) FROM sale_detail GROUP BY 1;次の結果が返されます。
+------------+------------+ | region | _c1 | +------------+------------+ | china | 300.6 | +------------+------------+
HAVING 句 (HAVING_condition)
having_condition はオプションです。ほとんどの場合、HAVING 句は集計関数と共に使用され、データをフィルタリングします。サンプルステートメント:
-- データレンダリング効果を表示するために、sale_detail テーブルにデータを挿入します。
INSERT INTO sale_detail PARTITION (sale_date='2014', region='shanghai') VALUES ('null','c5',null),('s6','c6',100.4),('s7','c7',100.5);
-- having_condition を集計関数と共に使用して、データをフィルタリングします。
SELECT region,SUM(total_price) FROM sale_detail
GROUP BY region
HAVING SUM(total_price)<305;次の結果が返されます。
+------------+------------+
| region | _c1 |
+------------+------------+
| china | 300.6 |
| shanghai | 200.9 |
+------------+------------+ORDER BY (ORDER_condition)
order_condition はオプションです。ORDER BY は、指定された共通列またはパーティションキー列に基づいてすべてのデータレコードをソートするために使用されます。ORDER BY は、指定された定数に基づいてすべてのデータレコードをソートするためにも使用できます。ORDER BY を使用する場合、次のルールに従う必要があります。
デフォルトでは、データは昇順にソートされます。データを降順にソートする場合、
DESCキーワードが必要です。デフォルトでは、
ORDER BYの後にLIMIT <number>が続き、出力に表示されるデータ行の数が制限されます。ORDER BY の後にLIMIT <number>が続かない場合、エラーが返されます。この LIMIT を回避することもできます。詳細については、LIMIT を参照してください。次のステートメントは、sale_detail テーブルからデータをクエリし、total_price 列の値に基づいてデータレコードを昇順にソートしてから、最初の 2 つのレコードを表示します。サンプルステートメント:
SELECT * FROM sale_detail ORDER BY total_price LIMIT 2;次の結果が返されます。
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ | s1 | c1 | 100.1 | 2013 | china | | s2 | c2 | 100.2 | 2013 | china | +------------+-------------+-------------+------------+------------+次のステートメントは、sale_detail テーブルからデータをクエリし、total_price 列の値に基づいてデータレコードを降順にソートしてから、最初の 2 つのレコードを表示します。サンプルステートメント:
SELECT * FROM sale_detail ORDER BY total_price DESC LIMIT 2;次の結果が返されます。
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ | s3 | c3 | 100.3 | 2013 | china | | s2 | c2 | 100.2 | 2013 | china | +------------+-------------+-------------+------------+------------+
データをソートするために
ORDER BYを使用する場合、NULL が最小値です。これは MySQL でも同様です。ただし、Oracle ではそうではありません。次のステートメントは、sale_detail テーブルからデータをクエリし、total_price 列の値に基づいてデータレコードを昇順にソートしてから、最初の 2 つのレコードを表示します。サンプルステートメント:
SELECT * FROM sale_detail ORDER BY total_price LIMIT 2;次の結果が返されます。
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ | s1 | c1 | 100.1 | 2013 | china | | s2 | c2 | 100.2 | 2013 | china | +------------+-------------+-------------+------------+------------+ORDER BYの後に、SELECT文の出力列のエイリアスが続きます。SELECT文の出力列のエイリアスを指定しない場合、この列の名前がこの列のエイリアスとして使用されます。次のステートメントは、
ORDER BYの後に出力列のエイリアスを追加します。サンプルステートメント:SELECT total_price AS t FROM sale_detail ORDER BY total_price LIMIT 3; -- 前のステートメントは、次のステートメントと同じです。 SELECT total_price AS t FROM sale_detail ORDER BY t LIMIT 3;次の結果が返されます。
+------------+ | t | +------------+ | 100.1 | | 100.2 | | 100.3 | +------------+SELECT 文の前に
SET hive.orderby.position.alias=true;コマンドを追加すると、ORDER BY句の整数定数は、SELECT文の列番号と見なされます。サンプルステートメント:-- このコマンドを次の SELECT 文と共に実行します。 SET odps.sql.orderby.position.alias=true; SELECT * FROM sale_detail ORDER BY 3 LIMIT 3;次の結果が返されます。
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ | s1 | c1 | 100.1 | 2013 | china | | s2 | c2 | 100.2 | 2013 | china | | s3 | c3 | 100.3 | 2013 | china | +------------+-------------+-------------+------------+------------+OFFSET句は、ORDER BY...LIMIT句と共に使用して、スキップする行数を指定できます。形式はORDER BY...LIMIT m OFFSET nで、ORDER BY...LIMIT n, mと省略できます。LIMIT mは、m 行のデータが返されることを指定します。OFFSET nは、データが返される前に n 行がスキップされることを指定します。行をスキップしたくない場合は、実行するステートメントでOFFSET 0を使用できます。また、OFFSET 句を指定せずにステートメントを実行することもできます。次のステートメントは、sale_detail テーブルのデータを total_price 列の値に基づいて昇順にソートし、3 行目から 3 行のデータを表示します。サンプルステートメント:
SELECT customer_id,total_price FROM sale_detail ORDER BY total_price LIMIT 3 OFFSET 2; -- 前のステートメントは、次のステートメントと同じです。 SELECT customer_id,total_price FROM sale_detail ORDER BY total_price LIMIT 2, 3;次の結果が返されます。
+-------------+-------------+ | customer_id | total_price | +-------------+-------------+ | c3 | 100.3 | +-------------+-------------+クエリされたデータには、3 行のデータのみが含まれています。この場合、3 行目のみが返されます。
範囲クラスタリングは、グローバルソートの高速化にも使用できます。ORDER BY が使用される一般的なシナリオでは、すべてのソート済みデータが同じインスタンス に配信され、グローバルソートが保証されます。ただし、これらのシナリオでは、同時処理を十分に活用できません。範囲クラスタリングのパーティション化ステップを使用して、同時グローバルソートを実装できます。グローバルソートを実行する場合、データをサンプリングし、データを範囲に分割し、各範囲のデータを並列にソートしてから、グローバルソートの結果を取得する必要があります。詳細については、「グローバルソートの高速化」をご参照ください。
DISTRIBUTE BY ハッシュパーティション (DISTRIBUTE_condition)
distribute_condition はオプションです。DISTRIBUTE BY は、特定の列の値に基づいてデータにハッシュパーティションを実行するために使用されます。
DISTRIBUTE BY は、マッパーの出力がリデューサー間でどのように配信されるかを制御します。同じデータが異なるリデューサーに配信されないようにするには、DISTRIBUTE BY を使用できます。これにより、同じデータグループが同じリデューサーに配信されます。
SELECT 文の出力列のエイリアスを指定する必要があります。SELECT 文を実行して列のデータをクエリし、この列のエイリアスが指定されていない場合、列名がエイリアスとして使用されます。サンプルステートメント:
-- 次のステートメントは、sale_detail テーブルから region 列の値をクエリし、region 列の値に基づいてデータにハッシュパーティションを実行します。
SELECT region FROM sale_detail DISTRIBUTE BY region;
-- 前のステートメントは、次のステートメントと同じです。
SELECT region AS r FROM sale_detail DISTRIBUTE BY region;
SELECT region AS r FROM sale_detail DISTRIBUTE BY r;SORT BY (SORT_condition)
sort_condition はオプションです。ほとんどの場合、SORT BY は DISTRIBUTE BY と共に使用されます。SORT BY を使用する場合、次のルールに従う必要があります。
デフォルトでは、データは昇順にソートされます。データを降順にソートする場合、
DESCキーワードが必要です。SORT BYの前にDISTRIBUTE BYがある場合、SORT BYは指定された列の値に基づいてDISTRIBUTE BYの結果をソートします。次のステートメントは、sale_detail テーブルから region 列と total_price 列の値をクエリし、region 列の値に基づいてクエリ結果にハッシュパーティションを実行してから、total_price 列の値に基づいてパーティション結果を昇順にソートします。サンプルステートメント:
-- データレンダリング効果を表示するために、sale_detail テーブルにデータを挿入します。 INSERT INTO sale_detail PARTITION (sale_date='2014', region='shanghai') VALUES ('null','c5',null),('s6','c6',100.4),('s7','c7',100.5); SELECT region,total_price FROM sale_detail DISTRIBUTE BY region SORT BY total_price;次の結果が返されます。
+------------+-------------+ | region | total_price | +------------+-------------+ | shanghai | NULL | | china | 100.1 | | china | 100.2 | | china | 100.3 | | shanghai | 100.4 | | shanghai | 100.5 | +------------+-------------+次のステートメントは、sale_detail テーブルから region 列と total_price 列の値をクエリし、region 列の値に基づいてクエリ結果にハッシュパーティションを実行してから、total_price 列の値に基づいてパーティション結果を降順にソートします。サンプルステートメント:
SELECT region,total_price FROM sale_detail DISTRIBUTE BY region SORT BY total_price DESC;次の結果が返されます。
+------------+-------------+ | region | total_price | +------------+-------------+ | shanghai | 100.5 | | shanghai | 100.4 | | china | 100.3 | | china | 100.2 | | china | 100.1 | | shanghai | NULL | +------------+-------------+
SORT BYの前にDISTRIBUTE BYがない場合、SORT BYは各リデューサーに配信されたデータをソートします。これにより、各リデューサーの出力データが順番にソートされ、ストレージ圧縮率が向上します。データの読み取り中にデータがフィルタリングされる場合、この方法ではディスクから読み取られるデータ量が削減され、後続のグローバルソートの効率が向上します。サンプルステートメント:
SELECT region,total_price FROM sale_detail SORT BY total_price DESC;次の結果が返されます。
+------------+-------------+ | region | total_price | +------------+-------------+ | china | 100.3 | | china | 100.2 | | china | 100.1 | | shanghai | 100.5 | | shanghai | 100.4 | | shanghai | NULL | +------------+-------------+
ORDER BY、DISTRIBUTE BY、または SORT BY句の列は、SELECT文の出力列のエイリアスで指定する必要があります。列エイリアスは中国語にすることができます。MaxCompute では、
ORDER BY、DISTRIBUTE BY、または SORT BY句はSELECT文の後に実行されます。したがって、ORDER BY、DISTRIBUTE BY、または SORT BY の列は、SELECT文の出力列のエイリアスで指定する必要があります。ORDER BYは、DISTRIBUTE BYまたはSORT BYと同時に使用できません。同様に、GROUP BYは、DISTRIBUTE BYまたはSORT BYと同時に使用できません。
LIMIT <number>
LIMIT <number> は省略可能です。number (limit <number> 内)は、表示可能な行数を制限する定数です。number の値は 32 ビット整数で、最大値は 2,147,483,647 です。
LIMIT <number> は、分散クエリシステムのデータのスキャンとフィルタリングに使用されます。LIMIT <number> を使用しても、返されるデータ量は削減されません。そのため、計算コストは削減されません。
次のセクションでは、LIMIT <number> の制限と、これらの制限を回避する方法について説明します。
ORDER BYは、LIMIT <number>と一緒に使用する必要があります。ORDER BYは、単一ノードのすべてのデータをソートします。 デフォルトでは、単一ノードが大量のデータを処理しないように、ORDER BY はLIMIT <number>と一緒に使用されます。 次の方法を使用して、このLIMITを回避できます。プロジェクトの
LIMITを回避するには、SETPROJECT odps.sql.validate.orderby.limit=false;コマンドを実行します。セッションの制限を回避するには、コミットして、実行する SQL 文で
SET odps.sql.validate.orderby.limit=false;コマンドを実行します。説明この
LIMITを回避した後、単一ノードにソートするデータが大量にある場合、より多くのリソースと時間が消費されます。
制限された行が表示されます。
SELECT文をLIMIT <number>句なしで実行した場合、またはLIMIT <number>句で指定された数値が表示可能な最大行数 (n) を超えた場合、最大 n 行が表示されます。表示可能な最大行数は、プロジェクトによって異なります。 次のいずれかの方法を使用して、最大数を制御できます。
プロジェクトデータ保護が無効になっている場合は、odpscmd config.ini ファイルを変更します。
odpscmd config.ini ファイルで
use_instance_tunnelを true に設定します。instance_tunnel_max_recordパラメーターが設定されていない場合、表示できる行数は制限されません。 それ以外の場合、表示できる行数はinstance_tunnel_max_recordパラメーターによって制限されます。instance_tunnel_max_recordパラメーターの最大値は 10000 です。 InstanceTunnel の詳細については、「使用上の注意」をご参照ください。プロジェクトデータ保護が有効になっている場合、表示できる行数は
READ_TABLE_MAX_ROWパラメーターによって制限されます。 このパラメーターの最大値は 10000 です。
説明SHOW SecurityConfiguration;コマンドを実行して、ProjectProtectionの値を表示できます。ProjectProtectionが true に設定されている場合は、ビジネス要件に基づいてプロジェクトデータ保護を無効にするかどうかを決定できます。SET ProjectProtection=false;コマンドを実行して、プロジェクトデータ保護を無効にすることができます。 デフォルトでは、ProjectProtectionは false に設定されています。 プロジェクトデータ保護の詳細については、「プロジェクトデータ保護」をご参照ください。
Window 句 (window_clause)
詳細については、「構文」をご参照ください。