MaxCompute vous permet d'utiliser des opérations JOIN pour joindre des tables et renvoyer les données qui satisfont aux conditions de jointure et de requête. Cette rubrique décrit les opérations JOIN suivantes : LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN, INNER JOIN, NATURAL JOIN, jointure implicite et jointures multiples.
Présentation
MaxCompute prend en charge les types d'opérations JOIN suivants :
-
LEFT OUTER JOINÉgalement appelée
LEFT JOIN. L'opération LEFT OUTER JOIN renvoie toutes les lignes de la table de gauche, y compris celles qui ne correspondent à aucune ligne de la table de droite.RemarqueDans une opération
JOIN, la table de gauche est généralement une grande table et la table de droite une petite table. Si certaines valeurs de la table de droite sont dupliquées, nous vous déconseillons d'exécuter plusieurs opérationsLEFT JOINconsécutives. En effet, cela peut provoquer une膨胀 des données (data bloat) et entraîner l'interruption de vos tâches. Si vous exécutez plusieurs opérationsLEFT JOINconsécutives, une膨胀 des données peut se produire et vos tâches peuvent être interrompues. -
RIGHT OUTER JOINÉgalement appelée
RIGHT JOIN. L'opération RIGHT OUTER JOIN renvoie toutes les lignes de la table de droite, y compris celles qui ne correspondent à aucune ligne de la table de gauche. -
FULL OUTER JOINÉgalement appelée
FULL JOIN. L'opération FULL OUTER JOIN renvoie toutes les lignes des tables de gauche et de droite. -
INNER JOINLe mot-clé
INNERpeut être omis. L'opérationINNER JOINrenvoie les lignes de données lorsqu'une correspondance existe entre les tables de gauche et de droite. -
NATURAL JOINLors d'une opération
NATURAL JOIN, les champs utilisés pour joindre deux tables sont déterminés en fonction des champs communs aux deux tables. MaxCompute prend en charge l'opérationOUTER NATURAL JOIN. Si vous utilisez la clauseUSING, l'opérationNATURAL JOINne renvoie les champs communs qu'une seule fois. -
Jointure implicite
Vous pouvez exécuter une opération
JOINimplicite sans avoir besoin de spécifier le mot-clé JOIN. -
Jointures multiples
MaxCompute prend en charge plusieurs opérations
JOIN. Vous pouvez utiliser des parenthèses () pour spécifier les priorités des opérationsJOIN. Une opérationJOINplacée entre parenthèses () possède une priorité plus élevée.
Si une instruction SQL contient la clause
WHEREet que vous utilisez la clauseJOINavant la clauseWHERE, l'opérationJOINest effectuée en premier. Ensuite, les résultats obtenus par l'opérationJOINsont filtrés selon les conditions spécifiées par la clauseWHERE. Le résultat final correspond à l'intersection des deux tables, et non à toutes les lignes d'une table.-
Vous pouvez utiliser le paramètre odps.task.sql.outerjoin.ppd pour contrôler si une condition non liée à la jointure dans la clause
OUTER JOIN ONdoit être utilisée comme donnée d'entrée de l'opérationJOIN. Vous pouvez configurer ce paramètre au niveau du projet ou de la session.Si vous définissez ce paramètre sur
false, la condition non liée à la jointure dans la clauseONest considérée comme une condition de la clauseWHEREpour la sous-requête de l'opération JOIN. Ce comportement n'est pas standard. Nous vous recommandons de spécifier la condition non liée à la jointure dans la clauseWHERE.Si vous définissez ce paramètre sur
false, les instructions SQL suivantes sont équivalentes. Si vous le définissez surtrue, les deux instructions SQL ne sont pas équivalentes.
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;
Remarques d'utilisation
Lors d'une opération JOIN, la condition de filtre key is not null de l'opération JOIN est automatiquement ajoutée pour le calcul. La ligne dont la valeur de la clé de jointure est nulle est filtrée après l'opération JOIN.
Limites
Lorsque vous exécutez une opération JOIN, tenez compte des limites suivantes :
MaxCompute ne prend pas en charge l'opération
CROSS JOIN. Une opération CROSS JOIN joint deux tables sans qu'il soit nécessaire de spécifier des conditions dans la clauseON.Vous devez utiliser des jointures par égalité et combiner les conditions à l'aide de
AND. Vous pouvez utiliser des jointures par inégalité ou combiner plusieurs conditions à l'aide deORdans une opérationMAPJOIN. Pour plus d'informations, consultez la section MAPJOIN.
Syntaxe
<table_reference> JOIN <table_factor> [<join_condition>]
| <table_reference> {LEFT OUTER|RIGHT OUTER|FULL OUTER|INNER|NATURAL} JOIN <table_reference> <join_condition>
table_reference : obligatoire. L'instruction de requête pour la table de gauche sur laquelle l'opération
JOINest effectuée. La valeur de ce paramètre est au formattable_name [alias] | table_query [alias] |....table_factor : obligatoire. L'instruction de requête pour la table de droite ou une table sur laquelle l'opération
JOINest effectuée. La valeur de ce paramètre est au formattable_name [alias] | table_subquery [alias] |....join_condition : facultatif. Une condition
JOINest une combinaison d'une ou plusieurs expressions d'égalité. La valeur de ce paramètre est au formaton equality_expression [and equality_expression]....equality_expressionreprésente une expression d'égalité.
Si des conditions d'élimination de partitions sont spécifiées dans la clause WHERE, l'élimination de partitions s'applique à la fois aux tables parentes et enfants. Si des conditions d'élimination de partitions sont spécifiées dans la clause ON, l'élimination de partitions s'applique uniquement à la table enfant. Par conséquent, une analyse complète de la table (full table scan) est effectuée pour la table parente. Pour plus d'informations, consultez la section Évaluer l'efficacité de l'élimination de partitions.
Données d'exemple
Des données source d'exemple sont fournies pour vous aider à mieux comprendre les exemples de cette rubrique. Les instructions suivantes montrent comment créer les tables sale_detail et sale_detail_jt et y insérer des données.
-- 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:
SET odps.sql.allow.fullscan=true;
SELECT * FROM sale_detail;
-- The following result is returned:
+------------+-------------+-------------+------------+------------+
| 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 |
+------------+-------------+-------------+------------+------------+
SET odps.sql.allow.fullscan=true;
SELECT * FROM sale_detail_jt;
-- The following result is returned:
+------------+-------------+-------------+------------+------------+
| 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;
Exemples
Les exemples suivants illustrent l'utilisation de JOIN sur la base des données d'exemple.
-
Exemple 1 : LEFT OUTER JOIN. Instructions d'exemple :
-- 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;Le résultat suivant est renvoyé :
+------------+------------+ | ashop | bshop | +------------+------------+ | s2 | s2 | | s1 | s1 | | s5 | NULL | +------------+------------+ -
Exemple 2 : RIGHT OUTER JOIN. Instructions d'exemple :
-- 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;Le résultat suivant est renvoyé :
+------------+------------+ | ashop | bshop | +------------+------------+ | s1 | s1 | | s2 | s2 | | NULL | s3 | | NULL | null | | NULL | s6 | | NULL | s7 | +------------+------------+ -
Exemple 3 : FULL OUTER JOIN. Instructions d'exemple :
-- 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;Le résultat suivant est renvoyé :
+------------+------------+ | ashop | bshop | +------------+------------+ | NULL | s3 | | NULL | s6 | | s2 | s2 | | NULL | null | | NULL | s7 | | s1 | s1 | | s5 | NULL | +------------+------------+ -
Exemple 4 : INNER JOIN. Instructions d'exemple :
-- 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;Le résultat suivant est renvoyé :
+------------+------------+ | ashop | bshop | +------------+------------+ | s2 | s2 | | s1 | s1 | +------------+------------+ -
Exemple 5 : NATURAL JOIN. Instructions d'exemple :
-- 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;Le résultat suivant est renvoyé :
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ | s1 | c1 | 100.1 | 2013 | china | | s2 | c2 | 100.2 | 2013 | china | +------------+-------------+-------------+------------+------------+ -
Exemple 6 : jointure implicite. Instructions d'exemple :
-- 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;Le résultat suivant est renvoyé :
+------------+-------------+-------------+------------+------------+------------+--------------+--------------+------------+------------+ | 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 | +------------+-------------+-------------+------------+------------+------------+--------------+--------------+------------+------------+ -
Exemple 7 : jointures multiples. Aucune priorité n'est spécifiée. Instructions d'exemple :
-- 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;Le résultat suivant est renvoyé :
+------------+-------------+-------------+------------+------------+ | 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 | +------------+-------------+-------------+------------+------------+ -
Exemple 8 : jointures multiples. Utilisez des parenthèses () pour spécifier les priorités des opérations JOIN. Instructions d'exemple :
-- 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;Le résultat suivant est renvoyé :
+------------+-------------+-------------+------------+------------+------------+--------------+--------------+------------+------------+------------+--------------+--------------+------------+------------+ | 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 | +------------+-------------+-------------+------------+------------+------------+--------------+--------------+------------+------------+------------+--------------+--------------+------------+------------+ -
Exemple 9 : Utilisez
JOINetWHEREpour interroger le nombre d'enregistrements dont la région est « china » et dont le champ shop_name a la même valeur dans les deux tables. Tous les enregistrements de la table sale_detail sont conservés. Instructions d'exemple :-- 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;Le résultat suivant est renvoyé :
+------------+-------------+-------------+--------------+ | 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 | +------------+-------------+-------------+--------------+Instruction d'exemple illustrant une utilisation incorrecte :
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";Le résultat suivant est renvoyé :
+------------+-------------+-------------+--------------+ | shop_name | customer_id | total_price | total_price2 | +------------+-------------+-------------+--------------+ | s1 | c1 | 100.1 | 100.1 | | s2 | c2 | 100.2 | 100.2 | +------------+-------------+-------------+--------------+Le résultat renvoyé correspond à l'intersection des deux tables, et non à toutes les lignes de la table sale_detail.