Données de test et ressources
movie_id d’une ligne de la table genres contient la valeur id d’une ligne de la table movies.
Il existe une relation de plusieurs à plusieurs entre les films et les acteurs.
Cette relation de plusieurs à plusieurs est normalisée en deux relations de un à plusieurs à l’aide de la table roles.
Chaque ligne de la table roles contient les valeurs des colonnes id des tables movies et actors.
Types de jointure pris en charge dans ClickHouse
INNER JOIN
INNER JOIN renvoie, pour chaque paire de lignes correspondant aux clés de jointure, les valeurs des colonnes de la ligne de la table de gauche, combinées avec les valeurs des colonnes de la ligne de la table de droite.
Si une ligne a plus d’une correspondance, toutes les correspondances sont renvoyées (ce qui signifie que le produit cartésien est généré pour les lignes dont les clés de jointure correspondent).
Cette requête trouve les genres de chaque film en joignant la table movies à la table genres :
Le mot-clé
INNER peut être omis.INNER JOIN peut être étendu ou modifié à l’aide de l’un des types de jointure suivants.
(LEFT / RIGHT / FULL) OUTER JOIN
LEFT OUTER JOIN se comporte comme INNER JOIN ; de plus, pour les lignes de la table de gauche qui n’ont pas de correspondance, ClickHouse renvoie des valeurs par défaut pour les colonnes de la table de droite.
Une requête RIGHT OUTER JOIN est similaire et renvoie également les valeurs des lignes non correspondantes de la table de droite, avec les valeurs par défaut pour les colonnes de la table de gauche.
Une requête FULL OUTER JOIN combine LEFT et RIGHT OUTER JOIN et renvoie les valeurs des lignes non correspondantes des tables de gauche et de droite, avec les valeurs par défaut pour les colonnes des tables de droite et de gauche, respectivement.
ClickHouse peut être configuré pour renvoyer des NULLs au lieu de valeurs par défaut (cependant, cela est moins recommandé pour des raisons de performances).
movies qui n’ont pas de correspondance dans la table genres et qui reçoivent donc (au moment de l’exécution de la requête) la valeur par défaut 0 pour la colonne movie_id :
Le mot-clé
OUTER peut être omis.CROSS JOIN
CROSS JOIN produit l’intégralité du produit cartésien des deux tables, sans tenir compte des clés de jointure.
Chaque ligne de la table de gauche est combinée avec chaque ligne de la table de droite.
La requête suivante combine donc chaque ligne de la table movies avec chaque ligne de la table genres :
WHERE pour associer les lignes correspondantes et reproduire le comportement de INNER JOIN afin de trouver les genres de chaque film :
CROSS JOIN consiste à spécifier plusieurs tables dans la clause FROM, séparées par des virgules.
ClickHouse réécrit un CROSS JOIN en INNER JOIN s’il existe des expressions de jointure dans la clause WHERE de la requête.
Vous pouvez le vérifier pour la requête d’exemple via EXPLAIN SYNTAX (qui renvoie la version syntaxiquement optimisée vers laquelle une requête est réécrite avant d’être exécutée) :
INNER JOIN dans la version de requête CROSS JOIN optimisée sur le plan syntaxique contient le mot-clé ALL, ajouté explicitement afin de préserver la sémantique de produit cartésien de CROSS JOIN même lorsqu’elle est réécrite en INNER JOIN, pour lequel le produit cartésien peut être désactivé.
OUTER peut être omis dans un RIGHT OUTER JOIN, et le mot-clé facultatif ALL peut être ajouté, vous pouvez écrire ALL RIGHT JOIN et cela fonctionnera parfaitement.
(LEFT / RIGHT) SEMI JOIN
LEFT SEMI JOIN renvoie les valeurs de colonne de chaque ligne de la table de gauche ayant au moins une correspondance sur la clé de jointure dans la table de droite.
Seule la première correspondance trouvée est renvoyée (le produit cartésien est désactivé).
Une requête RIGHT SEMI JOIN est similaire : elle renvoie les valeurs de toutes les lignes de la table de droite ayant au moins une correspondance dans la table de gauche, mais seule la première correspondance trouvée est renvoyée.
Cette requête trouve tous les acteurs et actrices ayant joué dans un film en 2023.
Notez qu’avec une jointure (INNER) classique, un même acteur ou une même actrice apparaîtrait plusieurs fois s’il ou elle avait eu plus d’un rôle en 2023 :
(LEFT / RIGHT) ANTI JOIN
LEFT ANTI JOIN renvoie les valeurs des colonnes de toutes les lignes non correspondantes de la table de gauche.
De même, un RIGHT ANTI JOIN renvoie les valeurs des colonnes de toutes les lignes non correspondantes de la table de droite.
Une autre formulation de l’exemple de requête de jointure externe précédent consiste à utiliser un anti join pour trouver les films qui n’ont pas de genre dans le jeu de données :
(LEFT / RIGHT / INNER) ANY JOIN
LEFT ANY JOIN combine LEFT OUTER JOIN et LEFT SEMI JOIN, ce qui signifie que ClickHouse renvoie les valeurs de colonnes pour chaque ligne de la table de gauche, soit associées aux valeurs de colonnes d’une ligne correspondante de la table de droite, soit aux valeurs de colonnes par défaut de la table de droite lorsqu’il n’existe aucune correspondance.
Si une ligne de la table de gauche a plus d’une correspondance dans la table de droite, ClickHouse renvoie uniquement les valeurs de colonnes combinées de la première correspondance trouvée (le produit cartésien est désactivé).
De même, RIGHT ANY JOIN combine RIGHT OUTER JOIN et RIGHT SEMI JOIN.
Et INNER ANY JOIN correspond à INNER JOIN avec le produit cartésien désactivé.
L’exemple suivant illustre LEFT ANY JOIN à l’aide d’un exemple abstrait utilisant deux tables temporaires (left_table et right_table) construites avec la values table function:
RIGHT ANY JOIN :
INNER ANY JOIN :
ASOF JOIN
ASOF JOIN permet des correspondances non exactes.
Si une ligne de la table de gauche n’a pas de correspondance exacte dans la table de droite, la ligne la plus proche de la table de droite est utilisée à la place.
C’est particulièrement utile pour l’analyse de séries temporelles et peut réduire considérablement la complexité des requêtes.
L’exemple suivant effectue une analyse de séries temporelles sur des données boursières.
Une table quotes contient les cotations de symboles boursiers à des moments précis de la journée.
Dans les données d’exemple, le prix est mis à jour toutes les 10 secondes.
Une table trades répertorie les transactions par symbole : un certain volume d’un symbole a été acheté à un instant précis :
Pour calculer le coût réel de chaque transaction, nous devons faire correspondre les transactions avec l’heure de cotation la plus proche.
C’est simple et concis avec l’ASOF JOIN : vous utilisez la clause ON pour spécifier une condition de correspondance exacte, et la clause AND pour définir la condition de correspondance la plus proche. Pour un symbole donné (correspondance exacte), vous recherchez dans la table quotes la ligne dont l’heure est la plus « proche », à l’instant exact d’une transaction sur ce symbole ou juste avant (correspondance non exacte) :
La clause
ON du ASOF JOIN est requise et spécifie une condition de correspondance exacte, en plus de la condition de correspondance non exacte de la clause AND.