MaxComputeでは、JOIN
操作を使用してテーブルを結合し、結合条件とクエリ条件を満たすデータを返すことができます。 このトピックでは、次のJOIN操作について説明します。LEFT OUTER JOIN、RIGHT OUTER JOIN、FULL OUTER JOIN、INNER JOIN、NATURAL JOIN、implicit JOIN、および複数のJOIN操作。
概要
MaxComputeは、次のタイプのJOIN
操作をサポートしています。
LEFT OUTER JOIN
LEFT JOIN
とも呼ばれます。 LEFT OUTER JOINは、右側のテーブルの行と一致しない行を含む、左側のテーブルのすべての行を返します。説明JOIN
操作では、ほとんどの場合、左側のテーブルは大きなテーブルであり、右側のテーブルは小さなテーブルです。 右側のテーブルの一部の行の値が重複している場合は、複数の連続したLEFT JOIN
操作を実行しないことを推奨します。 複数の連続したLEFT JOIN
操作を実行すると、データの膨張が発生し、ジョブが中断されることがあります。RIGHT OUTER JOIN
RIGHT JOIN
とも呼ばれます。 RIGHT OUTER JOINは、左側のテーブルの行と一致しない行を含む、右側のテーブルのすべての行を返します。FULL OUTER JOIN
FULL JOIN
とも呼ばれます。 FULL OUTER JOINは、左右両方のテーブルのすべての行を返します。INNER JOIN
INNER
キーワードは省略できます。INNER JOIN
は、左右のテーブルに一致がある場合、データ行を返します。NATURAL JOIN
NATURAL JOIN
オペレーションでは、2つのテーブルを結合するために使用されるフィールドは、2つのテーブルの共通フィールドに基づいて決定される。 MaxComputeはOUTER NATURAL JOIN
をサポートしています。USING
句を使用する場合、NATURAL JOIN
操作は共通フィールドを1回だけ返します。Implicit JOIN操作
JOINキーワードを指定しなくても、暗黙的な
JOIN
操作を実行できます。複数のJOIN操作
MaxComputeは複数の
JOIN
操作をサポートしています。 括弧 () を使用して、JOIN
操作の優先度を指定できます。 括弧 () で囲まれたJOIN
操作の方が優先度が高くなります。
SQL文に
WHERE
句が含まれていて、WHERE
句の前にJOIN
句を使用している場合、JOIN
操作が最初に実行されます。 次に、JOIN
操作から得られた結果は、WHERE
句で指定された条件に基づいてフィルタリングされます。 最終的な結果は、テーブル内のすべての行ではなく、2つのテーブルの共通部分です。odps.task.sql.outerjoin.ppdパラメーターを使用して、
OUTER JOIN ON
句のJOIN以外の条件をJOIN
操作の入力データとして使用するかどうかを制御できます。 このパラメーターは、プロジェクトまたはセッションレベルで設定できます。このパラメーターを
false
に設定した場合、ON
句のJOIN以外の条件は、JOIN操作のサブクエリのWHERE
句の条件と見なされます。 これは非標準的な動作です。WHERE
句でJOIN以外の条件を指定することを推奨します。このパラメーターを
false
に設定した場合、次のSQL文は同等です。 このパラメーターをtrue
に設定した場合、2つのSQL文は同等ではありません。
SELECT A.*, B.* FROM A LEFT JOIN B ON A.c1 = B.c1 and A.c2='xxx'; SELECT A.*, B.* FROM (SELECT * FROM A WHERE c2='xxx') A LEFT JOIN B ON A.c1 = B.c1;
使用上の注意
JOIN
操作では、JOIN
操作のフィルタ条件キーがnullではない
が自動的に追加されて計算されます。 結合キーの値がnullである行は、join操作後に除外されます。
制限事項
JOIN
操作を実行するときは、次の制限に注意してください。
MaxComputeは
CROSS JOIN
をサポートしていません。 CROSS JOIN操作では、ON
句で条件を指定せずに2つのテーブルを結合します。and
を使用して、equi-joinsと結合条件を使用する必要があります。 非equi結合を使用するか、MAPJOIN
操作でor
を使用して複数の条件を組み合わせることができます。 詳細については、「MAPJOIN」をご参照ください。
構文
<table_reference> join <table_factor> [<join_condition>]
| <table_reference> {left outer|right outer|full outer|inner|natural} join <table_reference> <join_condition>
table_reference: 必須です。
JOIN
操作が実行される左側のテーブルのクエリ文。 このパラメーターの値は、table_name [alias] | table_query [alias] |...
形式です。table_factor: 必須です。 正しいテーブルまたは
JOIN
操作が実行されるテーブルのクエリ文。 このパラメーターの値は、table_name [alias] | table_subquery [alias] |...
形式です。join_condition: オプションです。
JOIN
条件は、1つ以上の等式の組み合わせです。 このパラメーターの値は、on equality_expression [and equality_expression]...
形式です。equision_expression
は等式式です。
WHERE
句でパーティションプルーニング条件が指定されている場合、パーティションプルーニングは親テーブルと子テーブルの両方で有効になります。 ON
句でパーティションプルーニング条件が指定されている場合、パーティションプルーニングは子テーブルでのみ有効になります。 その結果、親テーブルに対してテーブル全体のスキャンが実行されます。 詳細については、「パーティションプルーニングが有効かどうかの確認」をご参照ください。
サンプルデータ
サンプルソースデータは、このトピックの例をよりよく理解するために提供されています。 次のステートメントは、sale_detailテーブルとsale_detail_jtテーブルを作成し、テーブルにデータを挿入する方法を示しています。
-- Create two partitioned tables named sale_detail and sale_detail_jt.
create table if not exists sale_detail
(
shop_name string,
customer_id string,
total_price double
)
partitioned by (sale_date string, region string);
create table if not exists sale_detail_jt
(
shop_name string,
customer_id string,
total_price double
)
partitioned by (sale_date string, region string);
-- Add partitions to the two tables.
alter table sale_detail add partition (sale_date='2013', region='china') partition (sale_date='2014', region='shanghai');
alter table sale_detail_jt add partition (sale_date='2013', region='china');
-- Insert data into the tables.
insert into sale_detail partition (sale_date='2013', region='china') values ('s1','c1',100.1),('s2','c2',100.2),('s3','c3',100.3);
insert into sale_detail partition (sale_date='2014', region='shanghai') values ('null','c5',null),('s6','c6',100.4),('s7','c7',100.5);
insert into sale_detail_jt partition (sale_date='2013', region='china') values ('s1','c1',100.1),('s2','c2',100.2),('s5','c2',100.2);
Query data from the sale_detail and sale_detail_jt tables. Sample statements:
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 |
| null | c5 | NULL | 2014 | shanghai |
| s6 | c6 | 100.4 | 2014 | shanghai |
| s7 | c7 | 100.5 | 2014 | shanghai |
+------------+-------------+-------------+------------+------------+
select * from sale_detail_jt;
+------------+-------------+-------------+------------+------------+
| shop_name | customer_id | total_price | sale_date | region |
+------------+-------------+-------------+------------+------------+
| s1 | c1 | 100.1 | 2013 | china |
| s2 | c2 | 100.2 | 2013 | china |
| s5 | c2 | 100.2 | 2013 | china |
+------------+-------------+-------------+------------+------------+
-- Create a table for the JOIN operation.
SET odps.sql.allow.fullscan=true;
create table shop as select shop_name, customer_id, total_price from sale_detail;
例
例1: LEFT OUTER JOIN。 サンプル文:
-- The full table scan feature must be enabled for partitioned tables. Otherwise, the JOIN operation fails. set odps.sql.allow.fullscan=true; -- Both the sale_detail_jt and sale_detail tables have the shop_name column. You must use aliases to distinguish between the columns in the SELECT statement. select a.shop_name as ashop, b.shop_name as bshop from sale_detail_jt a left outer join sale_detail b on a.shop_name=b.shop_name;
次の応答が返されます。
+------------+------------+ | ashop | bshop | +------------+------------+ | s2 | s2 | | s1 | s1 | | s5 | NULL | +------------+------------+
例2: RIGHT OUTER JOIN。 サンプル文:
-- The full table scan feature must be enabled for partitioned tables. Otherwise, the JOIN operation fails. set odps.sql.allow.fullscan=true; -- Both the sale_detail_jt and sale_detail tables have the shop_name column. You must use aliases to distinguish between the columns in the SELECT statement. select a.shop_name as ashop, b.shop_name as bshop from sale_detail_jt a right outer join sale_detail b on a.shop_name=b.shop_name;
次の応答が返されます。
+------------+------------+ | ashop | bshop | +------------+------------+ | NULL | s3 | | NULL | s6 | | NULL | null | | s2 | s2 | | NULL | s7 | | s1 | s1 | +------------+------------+
例3: FULL OUTER JOIN。 サンプル文:
-- The full table scan feature must be enabled for partitioned tables. Otherwise, the JOIN operation fails. set odps.sql.allow.fullscan=true; -- Both the sale_detail_jt and sale_detail tables have the shop_name column. You must use aliases to distinguish between the columns in the SELECT statement. select a.shop_name as ashop, b.shop_name as bshop from sale_detail_jt a full outer join sale_detail b on a.shop_name=b.shop_name;
次の応答が返されます。
+------------+------------+ | ashop | bshop | +------------+------------+ | NULL | s3 | | NULL | s6 | | s2 | s2 | | NULL | null | | NULL | s7 | | s1 | s1 | | s5 | NULL | +------------+------------+
例4: INNER JOIN。 サンプル文:
-- The full table scan feature must be enabled for partitioned tables. Otherwise, the JOIN operation fails. set odps.sql.allow.fullscan=true; -- Both the sale_detail_jt and sale_detail tables have the shop_name column. You must use aliases to distinguish between the columns in the SELECT statement. select a.shop_name as ashop, b.shop_name as bshop from sale_detail_jt a inner join sale_detail b on a.shop_name=b.shop_name;
次の応答が返されます。
+------------+------------+ | ashop | bshop | +------------+------------+ | s2 | s2 | | s1 | s1 | +------------+------------+
例5: NATURAL JOIN。 サンプル文:
-- The full table scan feature must be enabled for partitioned tables. Otherwise, the JOIN operation fails. set odps.sql.allow.fullscan=true; -- Perform a NATURAL JOIN operation. select * from sale_detail_jt natural join sale_detail; -- The preceding statement is equivalent to the following statement: select sale_detail_jt.shop_name as shop_name, sale_detail_jt.customer_id as customer_id, sale_detail_jt.total_price as total_price, sale_detail_jt.sale_date as sale_date, sale_detail_jt.region as region from sale_detail_jt inner join sale_detail on sale_detail_jt.shop_name=sale_detail.shop_name and sale_detail_jt.customer_id=sale_detail.customer_id and sale_detail_jt.total_price=sale_detail.total_price and sale_detail_jt.sale_date=sale_detail.sale_date and sale_detail_jt.region=sale_detail.region;
次の応答が返されます。
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ | s1 | c1 | 100.1 | 2013 | china | | s2 | c2 | 100.2 | 2013 | china | +------------+-------------+-------------+------------+------------+
例6: implicit JOIN。 サンプル文:
-- The full table scan feature must be enabled for partitioned tables. Otherwise, the JOIN operation fails. set odps.sql.allow.fullscan=true; -- Perform an implicit JOIN operation. select * from sale_detail_jt, sale_detail where sale_detail_jt.shop_name = sale_detail.shop_name; -- The preceding statement is equivalent to the following statement: select * from sale_detail_jt join sale_detail on sale_detail_jt.shop_name = sale_detail.shop_name;
次の応答が返されます。
+------------+-------------+-------------+------------+------------+------------+--------------+--------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | shop_name2 | customer_id2 | total_price2 | sale_date2 | region2 | +------------+-------------+-------------+------------+------------+------------+--------------+--------------+------------+------------+ | s2 | c2 | 100.2 | 2013 | china | s2 | c2 | 100.2 | 2013 | china | | s1 | c1 | 100.1 | 2013 | china | s1 | c1 | 100.1 | 2013 | china | +------------+-------------+-------------+------------+------------+------------+--------------+--------------+------------+------------+
例7: 複数のJOIN操作。 優先度は指定されていません。 サンプル文:
-- The full table scan feature must be enabled for partitioned tables. Otherwise, the JOIN operation fails. set odps.sql.allow.fullscan=true; -- Both the sale_detail_jt and sale_detail tables have the shop_name column. You must use aliases to distinguish between the columns in the SELECT statement. select a.* from sale_detail_jt a full outer join sale_detail b on a.shop_name=b.shop_name full outer join sale_detail c on a.shop_name=c.shop_name;
次の応答が返されます。
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ | s5 | c2 | 100.2 | 2013 | china | | NULL | NULL | NULL | NULL | NULL | | NULL | NULL | NULL | NULL | NULL | | NULL | NULL | NULL | NULL | NULL | | NULL | NULL | NULL | NULL | NULL | | NULL | NULL | NULL | NULL | NULL | | NULL | NULL | NULL | NULL | NULL | | s1 | c1 | 100.1 | 2013 | china | | NULL | NULL | NULL | NULL | NULL | | s2 | c2 | 100.2 | 2013 | china | | NULL | NULL | NULL | NULL | NULL | +------------+-------------+-------------+------------+------------+
例7: 複数のJOIN操作。 JOIN操作の優先度を指定するには、かっこ () を使用します。 サンプル文:
-- The full table scan feature must be enabled for partitioned tables. Otherwise, the JOIN operation fails. set odps.sql.allow.fullscan=true; -- Perform multiple JOIN operations. Use parentheses () to specify the priority. select * from shop join (sale_detail_jt join sale_detail on sale_detail_jt.shop_name = sale_detail.shop_name) on shop.shop_name=sale_detail_jt.shop_name;
次の応答が返されます。
+------------+-------------+-------------+------------+------------+------------+--------------+--------------+------------+------------+------------+--------------+--------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | shop_name2 | customer_id2 | total_price2 | sale_date2 | region2 | shop_name3 | customer_id3 | total_price3 | sale_date3 | region3 | +------------+-------------+-------------+------------+------------+------------+--------------+--------------+------------+------------+------------+--------------+--------------+------------+------------+ | s2 | c2 | 100.2 | 2013 | china | s2 | c2 | 100.2 | 2013 | china | s2 | c2 | 100.2 | 2013 | china | | s1 | c1 | 100.1 | 2013 | china | s1 | c1 | 100.1 | 2013 | china | s1 | c1 | 100.1 | 2013 | china | +------------+-------------+-------------+------------+------------+------------+--------------+--------------+------------+------------+------------+--------------+--------------+------------+------------+
例8:
JOIN
とWHERE
を使用して、2つのテーブルでリージョンがchinaでshop_nameフィールドの値が同じレコードの数を照会します。 sale_detailテーブル内のすべてのレコードが保持されます。 サンプル文:-- The full table scan feature must be enabled for partitioned tables. Otherwise, the JOIN operation fails. set odps.sql.allow.fullscan=true; -- Execute the following SQL statement: select a.shop_name ,a.customer_id ,a.total_price ,b.total_price from (select * from sale_detail where region = "china") a left join (select * from sale_detail_jt where region = "china") b on a.shop_name = b.shop_name;
次の応答が返されます。
+------------+-------------+-------------+--------------+ | shop_name | customer_id | total_price | total_price2 | +------------+-------------+-------------+--------------+ | s1 | c1 | 100.1 | 100.1 | | s2 | c2 | 100.2 | 100.2 | | s3 | c3 | 100.3 | NULL | +------------+-------------+-------------+--------------+
不正使用のサンプルステートメント:
select a.shop_name ,a.customer_id ,a.total_price ,b.total_price from sale_detail a left join sale_detail_jt b on a.shop_name = b.shop_name where a.region = "china" and b.region = "china";
次の応答が返されます。
+------------+-------------+-------------+--------------+ | shop_name | customer_id | total_price | total_price2 | +------------+-------------+-------------+--------------+ | s1 | c1 | 100.1 | 100.1 | | s2 | c2 | 100.2 | 100.2 | +------------+-------------+-------------+--------------+
返される結果は、sale_detailテーブルのすべての行ではなく、2つのテーブルの共通部分です。