Tous les produits
Search
Centre de documentation

MaxCompute:Subqueries

Dernière mise à jour :Aug 10, 2026

Une sous-requête est une instruction SELECT imbriquée dans une autre instruction SQL. Utilisez les sous-requêtes pour filtrer des lignes par rapport à un ensemble dynamique de valeurs, vérifier l'existence d'enregistrements associés, calculer des valeurs agrégées directement ou créer des tables dérivées pour des transformations complexes.

MaxCompute prend en charge six types de sous-requêtes : sous-requête de base, IN SUBQUERY, NOT IN SUBQUERY, EXISTS SUBQUERY, NOT EXISTS SUBQUERY et SCALAR SUBQUERY. Certains types sont automatiquement convertis en opérations JOIN lors de l'exécution. Comprendre quand cette conversion se produit — et quand elle ne se produit pas — vous aide à rédiger des requêtes efficaces et à éviter des résultats inattendus.

Concepts clés

Deux distinctions permettent de clarifier la plupart des différences de comportement entre les types de sous-requêtes.

Sous-requêtes corrélées et non corrélées

  • Une sous-requête corrélée fait référence à une ou plusieurs colonnes de la requête externe. MaxCompute l'évalue pour chaque ligne de la requête externe, en utilisant la valeur de la colonne externe comme filtre.

  • Une sous-requête non corrélée ne fait aucune référence à la requête externe. MaxCompute l'évalue une seule fois et réutilise le résultat.

Sous-requêtes scalaires et non scalaires

  • Une sous-requête scalaire renvoie exactement une ligne et une colonne. Le résultat peut être utilisé comme expression de valeur — dans une comparaison de clause WHERE ou dans une liste SELECT.

  • Une sous-requête non scalaire renvoie zéro ou plusieurs lignes. Elle est utilisée avec des opérateurs tels que IN, NOT IN, EXISTS ou NOT EXISTS.

Conversion JOIN et indice MAPJOIN

MaxCompute convertit les sous-requêtes SCALAR, IN, NOT IN, EXISTS et NOT EXISTS en opérations JOIN lorsque cela est possible. Si le résultat de la sous-requête est petit, ajoutez un indice MAPJOIN pour forcer l'algorithme JOIN par diffusion (broadcast) :

SELECT /*+ MAPJOIN(b) */ *
FROM sale_detail a
WHERE a.total_price IN (SELECT total_price FROM shop b);

Données d'exemple

Les exemples de cette rubrique utilisent les tables suivantes. Exécutez ces instructions pour configurer les données d'exemple :

-- Create a partitioned table named 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);

-- Add partitions.
ALTER TABLE sale_detail ADD PARTITION (sale_date='2013', region='china')
                        PARTITION (sale_date='2014', region='shanghai');

-- Insert sample data.
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);

Interrogez la table pour vérifier les données :

SET odps.sql.allow.fullscan=true;
SELECT * FROM sale_detail;

Résultat :

+------------+-------------+-------------+------------+------------+
| 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   |
+------------+-------------+-------------+------------+------------+

Sous-requête de base

Une sous-requête de base apparaît dans la clause FROM et agit comme une table dérivée. Vous pouvez la joindre à d'autres tables ou sous-requêtes comme n'importe quelle table régulière. Pour plus d'informations sur la syntaxe JOIN, consultez la section JOIN.

Syntaxe 1 — sous-requête en tant que table dérivée :

SELECT <select_expr> FROM (<select_statement>) [<sq_alias_name>];

Syntaxe 2 — sous-requête dans la liste de sélection (le résultat doit être une seule ligne) :

SELECT (<select_statement>) FROM <table_name>;

Paramètres

Paramètre Obligatoire Description
select_expr Oui Colonnes ou expressions à renvoyer, au format col1_name, col2_name, expression, ...
select_statement Oui La sous-requête. Pour la Syntaxe 2, la sous-requête doit renvoyer exactement une ligne. Consultez la section Syntaxe SELECT.
sq_alias_name Non Un alias pour la sous-requête
table_name Oui (Syntaxe 2) La table externe à interroger

Exemples

Exemple 1 — Syntaxe 1, sous-requête en tant que table dérivée :

SET odps.sql.allow.fullscan=true;
SELECT * FROM (SELECT shop_name FROM sale_detail) a;

Résultat :

+------------+
| shop_name  |
+------------+
| s1         |
| s2         |
| s3         |
| null       |
| s6         |
| s7         |
+------------+

Exemple 2 — Syntaxe 2, sous-requête à ligne unique dans la liste de sélection :

SET odps.sql.allow.fullscan=true;
SELECT (SELECT * FROM sale_detail WHERE shop_name='s1') FROM sale_detail;

Résultat :

+------------+-------------+-------------+------------+------------+
| shop_name  | customer_id | total_price | sale_date  | region     |
+------------+-------------+-------------+------------+------------+
| s1         | c1          | 100.1       | 2013       | china      |
| s1         | c1          | 100.1       | 2013       | china      |
| s1         | c1          | 100.1       | 2013       | china      |
| s1         | c1          | 100.1       | 2013       | china      |
| s1         | c1          | 100.1       | 2013       | china      |
| s1         | c1          | 100.1       | 2013       | china      |
+------------+-------------+-------------+------------+------------+

Exemple 3 — Syntaxe 1, sous-requête jointe à une autre table :

-- Create a shop table, then join it with sale_detail via a subquery.
CREATE TABLE shop AS SELECT shop_name, customer_id, total_price FROM sale_detail;

SELECT a.shop_name, a.customer_id, a.total_price
FROM (SELECT * FROM shop) a
JOIN sale_detail ON a.shop_name = sale_detail.shop_name;

Résultat :

+------------+-------------+-------------+
| shop_name  | customer_id | total_price |
+------------+-------------+-------------+
| null       | c5          | NULL        |
| s6         | c6          | 100.4       |
| s7         | c7          | 100.5       |
| s1         | c1          | 100.1       |
| s2         | c2          | 100.2       |
| s3         | c3          | 100.3       |
+------------+-------------+-------------+

IN SUBQUERY

La clause IN SUBQUERY filtre la requête externe pour ne conserver que les lignes dont la valeur d'une colonne correspond à l'une des valeurs renvoyées par la sous-requête. MaxCompute convertit IN SUBQUERY en LEFT SEMI JOIN lorsque la sous-requête est utilisée comme condition de jointure WHERE. Pour plus d'informations sur LEFT SEMI JOIN, consultez la section JOIN.

Syntaxe 1 — non corrélée :

SELECT <select_expr1> FROM <table_name1>
WHERE <select_expr2> IN (SELECT <select_expr3> FROM <table_name2>);

-- Equivalent LEFT SEMI JOIN:
SELECT <select_expr1> FROM <table_name1> <alias_name1>
LEFT SEMI JOIN <table_name2> <alias_name2>
ON <alias_name1>.<select_expr2> = <alias_name2>.<select_expr3>;
Si select_expr2 fait référence à une colonne de clé de partition, MaxCompute exécute la sous-requête en tant que tâche distincte au lieu de la convertir en LEFT SEMI JOIN. MaxCompute utilise ensuite les résultats de la sous-requête pour appliquer l'élagage des partitions sur table_name1 , de sorte que seules les partitions correspondantes sont lues.

Syntaxe 2 — corrélée (fait référence à une colonne externe) :

SELECT <select_expr1> FROM <table_name1>
WHERE <select_expr2> IN (
  SELECT <select_expr3> FROM <table_name2>
  WHERE <table_name1>.<col_name> = <table_name2>.<col_name>
);

MaxCompute V2.0 prend en charge les expressions qui font référence aux colonnes de la sous-requête et de la requête externe. Ces conditions corrélées deviennent partie intégrante de la condition ON dans l'opération SEMI JOIN. MaxCompute V1.0 ne prend pas en charge ces expressions.

Lorsque IN SUBQUERY ne peut pas être convertie en condition de jointure — par exemple, lorsqu'elle apparaît en dehors d'une clause WHERE ou lorsque la condition WHERE ne peut pas être exprimée sous forme de jointure — MaxCompute l'exécute en tant que tâche distincte. Les conditions corrélées ne sont pas prises en charge dans ce cas.

Syntax 3 — sous-requête multi-colonnes :

Utilisez plusieurs colonnes dans l'expression IN pour faire correspondre les résultats d'une sous-requête qui renvoie plusieurs colonnes. Cela élimine une opération JOIN par rapport à la division de la requête en sous-requêtes séparées. Les formes suivantes sont prises en charge :

  • Une instruction SELECT simple renvoyant plusieurs colonnes

  • Des fonctions d'agrégation dans la sous-requête

  • Des tuples constants

-- Multiple columns with a simple SELECT:
SELECT a, b FROM t1 WHERE (c, d) IN (SELECT a, b FROM t2 WHERE e = t1.e);

-- Multiple columns with aggregate functions:
SELECT a, b FROM t1 WHERE (c, d) IN (SELECT MAX(a), b FROM t2 WHERE e = t1.e GROUP BY b HAVING MAX(a) > 0);

-- Constant tuples:
SELECT a, b FROM t1 WHERE (c, d) IN ((1, 3), (1, 1));

Paramètres

Paramètre Obligatoire Description
select_expr1 Oui Colonnes à renvoyer depuis la requête externe
table_name1, table_name2 Oui Les noms des tables externe et interne
select_expr2, select_expr3 Oui Colonnes à comparer ; les valeurs sont mises en correspondance positionnellement
col_name Oui (Syntaxe 2) Colonne utilisée comme condition corrélée

Remarque d'utilisation

Les valeurs NULL dans le résultat de la sous-requête sont automatiquement exclues de la comparaison.

Exemples

Exemple 1 — Syntaxe 1 :

SET odps.sql.allow.fullscan=true;
SELECT * FROM sale_detail WHERE total_price IN (SELECT total_price FROM shop);

Résultat :

+-----------+-------------+-------------+-----------+----------+
| 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    |
| s6        | c6          | 100.4       | 2014      | shanghai |
| s7        | c7          | 100.5       | 2014      | shanghai |
+-----------+-------------+-------------+-----------+----------+

Exemple 2 — Syntaxe 2, condition corrélée :

SET odps.sql.allow.fullscan=true;
SELECT * FROM sale_detail
WHERE total_price IN (
  SELECT total_price FROM shop
  WHERE customer_id = shop.customer_id
);

Résultat :

+-----------+-------------+-------------+-----------+----------+
| 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    |
| s6        | c6          | 100.4       | 2014      | shanghai |
| s7        | c7          | 100.5       | 2014      | shanghai |
+-----------+-------------+-------------+-----------+----------+

Exemple 3 — Syntaxe 3, sous-requête multi-colonnes :

-- Set up sample tables.
CREATE TABLE IF NOT EXISTS t1(a BIGINT, b BIGINT, c BIGINT, d BIGINT, e BIGINT);
CREATE TABLE IF NOT EXISTS t2(a BIGINT, b BIGINT, c BIGINT, d BIGINT, e BIGINT);
INSERT INTO TABLE t1 VALUES (1,3,2,1,1),(2,2,1,3,1),(3,1,1,1,1),(2,1,1,0,1),(1,1,1,0,1);
INSERT INTO TABLE t2 VALUES (1,3,5,0,1),(2,2,3,1,1),(3,1,1,0,1),(2,1,1,0,1),(1,1,1,0,1);

-- Scenario 1: Simple SELECT with multiple columns.
SELECT a, b FROM t1 WHERE (c, d) IN (SELECT a, b FROM t2 WHERE e = t1.e);
-- Result:
-- +------------+------------+
-- | a          | b          |
-- +------------+------------+
-- | 1          | 3          |
-- | 2          | 2          |
-- | 3          | 1          |
-- +------------+------------+

-- Scenario 2: Aggregate functions.
SELECT a, b FROM t1 WHERE (c, d) IN (SELECT MAX(a), b FROM t2 WHERE e = t1.e GROUP BY b HAVING MAX(a) > 0);
-- Result:
-- +------------+------------+
-- | a          | b          |
-- +------------+------------+
-- | 2          | 2          |
-- +------------+------------+

-- Scenario 3: Constant tuples.
SELECT a, b FROM t1 WHERE (c, d) IN ((1, 3), (1, 1));
-- Result:
-- +------------+------------+
-- | a          | b          |
-- +------------+------------+
-- | 2          | 2          |
-- | 3          | 1          |
-- +------------+------------+

NOT IN SUBQUERY

La clause NOT IN SUBQUERY filtre la requête externe pour ne conserver que les lignes dont la valeur d'une colonne ne correspond à aucune valeur renvoyée par la sous-requête. MaxCompute convertit NOT IN SUBQUERY en LEFT ANTI JOIN lorsqu'elle est utilisée comme condition de jointure WHERE. Pour plus d'informations sur LEFT ANTI JOIN, consultez la section JOIN.

Important

Si une ligne de la table externe contient une valeur NULL dans la colonne comparée, l'expression NOT IN prend la valeur NULL pour cette ligne, et la condition WHERE échoue. Aucune ligne n'est renvoyée dans ce cas. Ce comportement diffère de celui de LEFT ANTI JOIN, qui gère les valeurs NULL différemment.

Syntaxe 1 — non corrélée :

SELECT <select_expr1> FROM <table_name1>
WHERE <select_expr2> NOT IN (SELECT <select_expr2> FROM <table_name2>);

-- Equivalent LEFT ANTI JOIN:
SELECT <select_expr1> FROM <table_name1> <alias_name1>
LEFT ANTI JOIN <table_name2> <alias_name2>
ON <alias_name1>.<select_expr1> = <alias_name2>.<select_expr2>;
Si select_expr2 fait référence à une colonne de clé de partition, MaxCompute exécute la sous-requête en tant que tâche distincte au lieu de la convertir en LEFT ANTI JOIN. L'élagage des partitions s'applique toujours : les partitions dont les clés ne figurent pas dans le résultat de la sous-requête ne sont pas lues.

Syntaxe 2 — corrélée :

SELECT <select_expr1> FROM <table_name1>
WHERE <select_expr2> NOT IN (
  SELECT <select_expr2> FROM <table_name2>
  WHERE <table_name2_colname> = <table_name1>.<colname>
);

MaxCompute V2.0 prend en charge les expressions qui font référence aux colonnes de la sous-requête et de la requête externe. Ces conditions corrélées deviennent partie intégrante de la condition ON dans l'opération ANTI JOIN. MaxCompute V1.0 ne prend pas en charge ces expressions.

Lorsque NOT IN SUBQUERY ne peut pas être convertie en condition de jointure — par exemple, lorsqu'elle apparaît en dehors d'une clause WHERE ou lorsque la condition WHERE inclut un opérateur AND conjointement avec NOT IN — MaxCompute l'exécute en tant que tâche distincte. Les conditions corrélées ne sont pas prises en charge dans ce cas.

Syntax 3 — sous-requête multi-colonnes :

Utilisez plusieurs colonnes dans l'expression NOT IN pour faire correspondre les résultats d'une sous-requête qui renvoie plusieurs colonnes. Les formes suivantes sont prises en charge :

  • Une instruction SELECT simple renvoyant plusieurs colonnes

  • Des fonctions d'agrégation dans la sous-requête

  • Des tuples constants

Paramètres

Paramètre Obligatoire Description
select_expr1 Oui Colonnes à renvoyer depuis la requête externe
table_name1, table_name2 Oui Les noms des tables externe et interne
select_expr2, select_expr3 Oui Colonnes à comparer ; les valeurs sont mises en correspondance positionnellement
col_name Oui (Syntaxe 2) Colonne utilisée comme condition corrélée

Remarque d'utilisation

Les valeurs NULL dans le résultat de la sous-requête sont automatiquement exclues de la comparaison.

Exemples

Exemple 1 — Syntaxe 1 :

-- Create a shop1 table with an extra row not in sale_detail.
CREATE TABLE shop1 AS SELECT shop_name, customer_id, total_price FROM sale_detail;
INSERT INTO shop1 VALUES ('s8','c1',100.1);

SELECT * FROM shop1 WHERE shop_name NOT IN (SELECT shop_name FROM sale_detail);

Résultat :

+------------+-------------+-------------+
| shop_name  | customer_id | total_price |
+------------+-------------+-------------+
| s8         | c1          | 100.1       |
+------------+-------------+-------------+

Exemple 2 — Syntaxe 2, condition corrélée :

SET odps.sql.allow.fullscan=true;
SELECT * FROM shop1
WHERE shop_name NOT IN (
  SELECT shop_name FROM sale_detail
  WHERE customer_id = shop1.customer_id
);

Résultat :

+------------+-------------+-------------+
| shop_name  | customer_id | total_price |
+------------+-------------+-------------+
| s8         | c1          | 100.1       |
+------------+-------------+-------------+

Exemple 3 — NOT IN SUBQUERY qui ne peut pas être convertie en ANTI JOIN :

Lorsque la clause WHERE combine NOT IN avec une condition AND, MaxCompute ne peut pas convertir la sous-requête en LEFT ANTI JOIN et l'exécute plutôt en tant que tâche distincte.

SET odps.sql.allow.fullscan=true;
SELECT * FROM shop1
WHERE shop_name NOT IN (SELECT shop_name FROM sale_detail)
  AND total_price < 100.3;

Résultat :

+------------+-------------+-------------+
| shop_name  | customer_id | total_price |
+------------+-------------+-------------+
| s8         | c1          | 100.1       |
+------------+-------------+-------------+

Exemple 4 — Les valeurs NULL dans la table externe empêchent le renvoi de lignes :

-- Create a sale table that includes a row with NULL in shop_name.
CREATE TABLE IF NOT EXISTS sale
(
  shop_name     STRING,
  customer_id   STRING,
  total_price   DOUBLE
)
PARTITIONED BY (sale_date STRING, region STRING);

ALTER TABLE sale ADD PARTITION (sale_date='2013', region='china');
INSERT INTO sale PARTITION (sale_date='2013', region='china')
VALUES ('null','null',null),('s2','c2',100.2),('s3','c3',100.3),('s8','c8',100.8);

SET odps.sql.allow.fullscan=true;
SELECT * FROM sale WHERE shop_name NOT IN (SELECT shop_name FROM sale_detail);

Résultat : Aucune ligne renvoyée car la valeur NULL dans shop_name fait que l'expression NOT IN prend la valeur NULL pour chaque ligne.

+------------+-------------+-------------+------------+------------+
| shop_name  | customer_id | total_price | sale_date  | region     |
+------------+-------------+-------------+------------+------------+
+------------+-------------+-------------+------------+------------+

Exemple 5 — Syntaxe 3, sous-requête multi-colonnes :

-- Use the same t1, t2 tables from the IN SUBQUERY examples.

-- Scenario 1: Simple SELECT with multiple columns.
SELECT a, b FROM t1 WHERE (c, d) NOT IN (SELECT a, b FROM t2 WHERE e = t1.e);
-- Result:
-- +------------+------------+
-- | a          | b          |
-- +------------+------------+
-- | 2          | 1          |
-- | 1          | 1          |
-- +------------+------------+

-- Scenario 2: Aggregate functions.
SELECT a, b FROM t1 WHERE (c, d) NOT IN (SELECT MAX(a), b FROM t2 WHERE e = t1.e GROUP BY b HAVING MAX(a) > 0);
-- Result:
-- +------------+------------+
-- | a          | b          |
-- +------------+------------+
-- | 1          | 3          |
-- | 3          | 1          |
-- | 2          | 1          |
-- | 1          | 1          |
-- +------------+------------+

-- Scenario 3: Constant tuples.
SELECT a, b FROM t1 WHERE (c, d) NOT IN ((1, 3), (1, 1));
-- Result:
-- +------------+------------+
-- | a          | b          |
-- +------------+------------+
-- | 1          | 3          |
-- | 2          | 1          |
-- | 1          | 1          |
-- +------------+------------+

EXISTS SUBQUERY

La clause EXISTS SUBQUERY renvoie les lignes de la requête externe pour lesquelles la sous-requête renvoie au moins une ligne. Si la sous-requête ne renvoie aucune ligne, la ligne externe est exclue.

MaxCompute prend en charge EXISTS SUBQUERY uniquement dans les clauses WHERE avec des conditions corrélées. La sous-requête est convertie en LEFT SEMI JOIN au moment de l'exécution.

Syntaxe

SELECT <select_expr> FROM <table_name1>
WHERE EXISTS (
  SELECT <select_expr> FROM <table_name2>
  WHERE <table_name2_colname> = <table_name1>.<colname>
);

Paramètres

Paramètre Obligatoire Description
select_expr Oui Colonnes à renvoyer
table_name1, table_name2 Oui Les noms des tables externe et interne
col_name Oui Colonne utilisée comme condition corrélée

Remarque d'utilisation

Les valeurs NULL dans le résultat de la sous-requête sont automatiquement exclues.

Exemple

SET odps.sql.allow.fullscan=true;
SELECT * FROM sale_detail
WHERE EXISTS (
  SELECT * FROM shop WHERE customer_id = sale_detail.customer_id
);

-- Equivalent LEFT SEMI JOIN:
SELECT * FROM sale_detail a LEFT SEMI JOIN shop b ON a.customer_id = b.customer_id;

Résultat :

+------------+-------------+-------------+------------+------------+
| shop_name  | customer_id | total_price | sale_date  | region     |
+------------+-------------+-------------+------------+------------+
| null       | c5          | NULL        | 2014       | shanghai   |
| s6         | c6          | 100.4       | 2014       | shanghai   |
| s7         | c7          | 100.5       | 2014       | shanghai   |
| s1         | c1          | 100.1       | 2013       | china      |
| s2         | c2          | 100.2       | 2013       | china      |
| s3         | c3          | 100.3       | 2013       | china      |
+------------+-------------+-------------+------------+------------+

NOT EXISTS SUBQUERY

La clause NOT EXISTS SUBQUERY est l'inverse de EXISTS SUBQUERY. Elle renvoie les lignes de la requête externe pour lesquelles la sous-requête ne renvoie aucune ligne.

MaxCompute prend en charge NOT EXISTS SUBQUERY uniquement dans les clauses WHERE avec des conditions corrélées. La sous-requête est convertie en LEFT ANTI JOIN au moment de l'exécution.

Syntaxe

SELECT <select_expr> FROM <table_name1>
WHERE NOT EXISTS (
  SELECT <select_expr> FROM <table_name2>
  WHERE <table_name2_colname> = <table_name1>.<colname>
);

Paramètres

Paramètre Obligatoire Description
select_expr Oui Colonnes à renvoyer
table_name1, table_name2 Oui Les noms des tables externe et interne
col_name Oui Colonne utilisée comme condition corrélée

Remarque d'utilisation

Les valeurs NULL dans le résultat de la sous-requête sont automatiquement exclues.

Exemple

SET odps.sql.allow.fullscan=true;
SELECT * FROM sale_detail
WHERE NOT EXISTS (
  SELECT * FROM shop WHERE shop_name = sale_detail.shop_name
);

-- Equivalent LEFT ANTI JOIN:
SELECT * FROM sale_detail a LEFT ANTI JOIN shop b ON a.shop_name = b.shop_name;

Résultat : Aucune ligne, car chaque ligne de sale_detail possède une valeur shop_name correspondante dans shop.

+------------+-------------+-------------+------------+------------+
| shop_name  | customer_id | total_price | sale_date  | region     |
+------------+-------------+-------------+------------+------------+
+------------+-------------+-------------+------------+------------+

SCALAR SUBQUERY

Une sous-requête scalaire renvoie exactement une ligne et une colonne. Le résultat peut être utilisé comme expression de valeur dans une comparaison de clause WHERE ou dans la liste SELECT. MaxCompute convertit les sous-requêtes scalaires en opérations JOIN lorsque cela est possible. Si une sous-requête scalaire qui renvoie une ligne comporte un seul opérateur MAX ou MIN imbriqué à l'extérieur, le résultat ne change pas.

Le type de retour doit être déterminable au moment de la compilation. Si MaxCompute ne peut confirmer que la sous-requête renvoie une seule ligne qu'au moment de l'exécution, le compilateur signale une erreur. Les modèles suivants satisfont à l'exigence de compilation :

  • La liste SELECT de la sous-requête scalaire utilise des fonctions d'agrégation qui ne sont pas imbriquées dans une fonction table définie par l'utilisateur (UDTF)

  • La sous-requête scalaire utilise des fonctions d'agrégation sans clause GROUP BY

SCALAR SUBQUERY prend également en charge les résultats multi-colonnes, avec les règles suivantes :

  • Une sous-requête scalaire multi-colonnes dans la liste SELECT doit utiliser uniquement la comparaison d'égalité

  • Les colonnes d'une sous-requête scalaire multi-colonnes peuvent être de type booléen, mais seule la comparaison d'égalité est prise en charge

  • Une clause WHERE peut comparer les résultats d'une sous-requête scalaire multi-colonnes, mais seule la comparaison d'égalité est prise en charge

Syntaxe

SELECT <select_expr> FROM <table_name1>
WHERE (SELECT COUNT(*) FROM <table_name2>
       WHERE <table_name2_colname> = <table_name1>.<colname>) <scalar_operator> <scalar_value>;

-- Equivalent JOIN form:
SELECT <table_name1>.<select_expr>
FROM <table_name1>
LEFT SEMI JOIN (
  SELECT <colname>, COUNT(*) FROM <table_name2>
  GROUP BY <colname>
  HAVING COUNT(*) <scalar_operator> <scalar_value>
) <table_name2> ON <table_name1>.<colname> = <table_name2>.<colname>;
L'expression SELECT COUNT(*) FROM <table_name2> WHERE <table_name2_colname> = <table_name1>.<colname> renvoie un ensemble de lignes, mais comme la requête utilise un agrégat scalaire, le résultat est toujours une valeur unique. Sous cette forme, MaxCompute convertit la sous-requête scalaire en une jointure.

Paramètres

Paramètre Obligatoire Description
select_expr Oui Colonnes à renvoyer
table_name1, table_name2 Oui Les noms des tables externe et interne
col_name Oui Colonne utilisée comme condition corrélée
scalar_operator Oui Un opérateur de comparaison : >, <, =, >= ou <=
scalar_value Oui La valeur scalaire à laquelle comparer

Limitations

SCALAR SUBQUERY ne peut être utilisée que dans une clause WHERE, et non comme expression autonome dans la liste de sélection lorsqu'elle fait référence à des colonnes externes.

L'imbrication à plusieurs niveaux est autorisée, mais seule la référence de colonne la plus externe est accessible :

-- Valid: references t1 from the outermost subquery level.
SELECT * FROM t1 WHERE (SELECT COUNT(*) FROM t2 WHERE t1.a = t2.a) = 3;

-- Invalid: t1 is referenced from within a nested subquery — two levels deep.
SELECT * FROM t1 WHERE (SELECT COUNT(*) FROM t2 WHERE (SELECT COUNT(*) FROM t3 WHERE t3.a = t1.a) = 2) = 3;

Les modèles suivants sont également invalides — la liste SELECT d'une sous-requête scalaire ne peut pas faire référence à des colonnes externes :

-- Invalid: references outer column t1.b in the SELECT list.
SELECT * FROM t1 WHERE (SELECT t1.b + COUNT(*) FROM t2) = 3;

-- Invalid: SELECT list references outer column.
SELECT (SELECT COUNT(t1.a) FROM t2 WHERE t2.a = t1.a) FROM t1;
SELECT (SELECT t1.a FROM t2 WHERE t2.a = t1.a) FROM t1;

Exemples

Exemple 1 — comparaison de comptage agrégé :

SET odps.sql.allow.fullscan=true;
SELECT * FROM shop
WHERE (SELECT COUNT(*) FROM sale_detail WHERE sale_detail.shop_name = shop.shop_name) >= 1;

Résultat :

+------------+-------------+-------------+
| shop_name  | customer_id | total_price |
+------------+-------------+-------------+
| s1         | c1          | 100.1       |
| s2         | c2          | 100.2       |
| s3         | c3          | 100.3       |
| null       | c5          | NULL        |
| s6         | c6          | 100.4       |
| s7         | c7          | 100.5       |
+------------+-------------+-------------+

Exemple 2 — sous-requête scalaire multi-colonnes :

-- Set up sample tables.
CREATE TABLE IF NOT EXISTS ts(a BIGINT, b BIGINT, c DOUBLE);
CREATE TABLE IF NOT EXISTS t(a BIGINT, b BIGINT, c DOUBLE);
INSERT INTO TABLE ts VALUES (1,3,4.0),(1,3,3.0);
INSERT INTO TABLE t VALUES (1,3,4.0),(1,3,5.0);

-- Scenario 1: Multi-column scalar subquery in the SELECT list (equality only).
-- Invalid: SELECT (SELECT a, b FROM t WHERE c > ts.c) AS (a, b), a FROM ts;
SELECT (SELECT a, b FROM t WHERE c = ts.c) AS (a, b), a FROM ts;
-- Result:
-- +------------+------------+------------+
-- | a          | b          | a2         |
-- +------------+------------+------------+
-- | 1          | 3          | 1          |
-- | NULL       | NULL       | 1          |
-- +------------+------------+------------+

-- Scenario 2: Boolean expression comparison (equality only).
-- Invalid: SELECT (a,b) > (SELECT a,b FROM ts WHERE c = t.c) FROM t;
SELECT (a,b) = (SELECT a,b FROM ts WHERE c = t.c) FROM t;
-- Result:
-- +------+
-- | _c0  |
-- +------+
-- | true |
-- | false|
-- +------+

-- Scenario 3: Multi-column WHERE comparison (equality only).
-- Invalid: SELECT * FROM t WHERE (a,b) > (SELECT a,b FROM ts WHERE c = t.c);
SELECT * FROM t WHERE c > 3.0 AND (a,b) = (SELECT a,b FROM ts WHERE c = t.c);
-- Result:
-- +------------+------------+------------+
-- | a          | b          | c          |
-- +------------+------------+------------+
-- | 1          | 3          | 4.0        |
-- +------------+------------+------------+

SELECT * FROM t WHERE c > 3.0 OR (a,b) = (SELECT a,b FROM ts WHERE c = t.c);
-- Result:
-- +------------+------------+------------+
-- | a          | b          | c          |
-- +------------+------------+------------+
-- | 1          | 3          | 4.0        |
-- | 1          | 3          | 5.0        |
-- +------------+------------+------------+

Limitations

Les limitations suivantes s'appliquent à tous les types de sous-requêtes :

Type de sous-requête Limitation
EXISTS SUBQUERY Pris en charge uniquement dans les clauses WHERE avec des conditions corrélées
NOT EXISTS SUBQUERY Pris en charge uniquement dans les clauses WHERE avec des conditions corrélées
IN SUBQUERY (non-JOIN) Conditions corrélées non prises en charge lorsque la sous-requête s'exécute en tant que tâche distincte
NOT IN SUBQUERY (non-JOIN) Conditions corrélées non prises en charge lorsque la sous-requête s'exécute en tant que tâche distincte
SCALAR SUBQUERY Utilisable uniquement dans les clauses WHERE ; la liste SELECT de la sous-requête ne peut pas faire référence à des colonnes externes
SCALAR SUBQUERY (multi-niveaux) Seule la référence de colonne externe la plus haute est accessible
SCALAR SUBQUERY (multi-colonnes) Seule la comparaison d'égalité est prise en charge
MaxCompute V1.0 IN SUBQUERY et NOT IN SUBQUERY ne prennent pas en charge les expressions qui font référence aux colonnes de la sous-requête et de la requête externe

Étapes suivantes

Un grand nombre de sous-requêtes ou des modèles de sous-requêtes inefficaces peuvent ralentir les requêtes dans les environnements Big Data. Envisagez ces alternatives :

  • Remplacez les sous-requêtes fréquemment réutilisées par des tables temporaires ou des vues matérialisées pour éviter les recalculs. Consultez la section Recommandations et gestion des vues matérialisées.

  • Réécrivez plusieurs sous-requêtes sous la forme d'une seule jointure JOIN pour réduire la charge des tâches. Consultez la section JOIN.