2nd Dec 2022 9 minutes de lecture Comment écrire des CTEs multiples en SQL Tihomir Babic sql apprendre sql cte Table des matières Présentation des données Deux CTEs : Indépendant Deux CTE : L'un référençant l'autre Deux CTEs : L'un des CTE est récursif. Multipliez encore la puissance des CTEs Exploitez tout le potentiel des CTE en en combinant deux ou plusieurs dans une seule requête SQL. Les expressions de table communes, ou CTE, peuvent être un outil SQL puissant. Lorsque vous écrivez deux (ou même plus) CTE ensemble, cette puissance se multiplie. Dans cet article, je vais vous montrer trois façons d'écrire plusieurs CTE : L'utilisation de deux CTE indépendants dans une requête SQL. Utilisation de deux CTE où le deuxième CTE fait référence au premier. Utilisation de deux CTE dont l'un est récursif. Si vous n'êtes pas familier avec les CTE, je vous recommande notre cours interactif Common Table Expressions, qui couvre tous les types de CTE, y compris les CTE récursifs, dans 114 exercices pratiques. Vous pouvez lire ce cours dans un épisode de notre série de cours du mois. Si vous souhaitez rafraîchir rapidement vos connaissances, ces articles sur les CTE et les cas où vous devez les utiliser constituent un bon point de départ. Présentation des données Je vais vous montrer les exemples de CTE sur un jeu de données composé de deux tables. La première table est cars. Elle contient des données sur les voitures fabriquées par Renault et Nissan. Ses colonnes sont : id - L'ID de la voiture et la clé primaire (PK) de la table. car_make - Le fabricant de la voiture. model - Le modèle de la voiture. motor_type - Les détails sur le type de moteur du modèle. year_of_production - L'année de fabrication de la voiture. Voici un exemple de données de la table : idcar_makemodelmotor_typeyear_of_production 1RenaultClio1.0 L H5Dt turbo I32022 2RenaultClio1.0 L H5Dt turbo I32021 3RenaultClio1.3 L H5Ht turbo I42022 4RenaultClio1.3 L H5Ht turbo I42021 La deuxième table, ventes_voitures, a ces colonnes : id - L'ID de l'information sur la vente et la clé primaire (PK) de la table. report_period - La date de la déclaration de vente. sales - Le nombre de voitures vendues. cars_id - La clé étrangère (FK) qui fait référence à la table cars. Quelques exemples de données de la table : idreport_periodsalescars_id 12021-10-314592 22021-11-305122 32021-12-314992 42022-01-315602 Deux CTEs : Indépendant Dans ce premier exemple, je vais vous montrer comment afficher le total des ventes dans son ensemble ainsi que par marque avec deux CTE indépendants. Le code se trouve ici : WITH sales_per_make AS ( SELECT car_make, SUM(sales) AS total_sales_per_make FROM cars c JOIN car_sales cs ON c.id = cs.cars_id GROUP BY car_make ), sales_sum AS ( SELECT SUM(sales) AS total_sales FROM car_sales ) SELECT car_make, total_sales_per_make, total_sales FROM sales_per_make, sales_sum ss; Je commence à écrire le premier CTE comme si c'était le seul et unique CTE de ma requête. Le nom du CTE , sales_per_makesuit le mot clé WITH, puis vient le mot clé AS. Après cela, j'écris entre parenthèses ce que je veux que le CTE fasse. Dans ce cas, j'utilise la fonction d'agrégation SUM() pour trouver les ventes par marque de voiture. Pour cela, je dois joindre les deux tables que j'ai à ma disposition. Le deuxième CTE vient ensuite. L'essentiel ici est qu'une virgule doit séparer les deux CTE. Ensuite, le deuxième CTE ne commence pas par le mot clé WITH mais immédiatement par le nom du deuxième CTE. Je l'ai nommé sales_sum. L'instruction SELECT entre parenthèses calcule les ventes totales de toutes les marques de voitures. Ces deux CTE sont indépendants car le second CTE ne fait pas référence au premier. Pour utiliser ces requêtes, je dois écrire une déclaration SELECT (la requête principale) qui les référence. C'est la même chose que lorsque vous n'écrivez qu'un seul CTE. L'instruction SELECT joint ici les résultats des deux CTE pour obtenir cette sortie : car_maketotal_sales_per_maketotal_sales Renault176,569361,928 Nissan185,359361,928 Le résultat signifie que les concessionnaires ont vendu 176 569 voitures Renault et 185 359 voitures Nissan, pour un total de 361 928 voitures. Vous voyez maintenant que l'écriture de deux CTE n'est pas si difficile. Cependant, il existe certains pièges lors de l'utilisation de plusieurs CTE dans une requête. Voici les principaux éléments auxquels vous devez faire attention lorsque vous écrivez plusieurs CTE : N'utilisez qu'un seul WITH. Séparez les CTE par des virgules. N'utilisez pas de virgule avant la requête principale. Il n'y a qu'une seule requête principale. Les CTE multiples ne fonctionnent que si vous écrivez le mot-clé WITH une seule fois. Mais ce n'est pas n'importe où que vous le voulez. Vous devez l'écrire avant le premier CTE. Le deuxième CTE et tout CTE suivant commencent par le nom des CTE respectifs, contrairement au premier CTE qui commence par le mot-clé WITH. Le premier CTE est séparé du second par une virgule. Il en va de même si vous écrivez plus de deux CTE : tous les CTE sont séparés par une virgule. Cependant, quel que soit le nombre de CTE, il n'y a pas de virgule entre le dernier CTE et la requête principale. Enfin, il n'y a qu'une seule requête principale. Quel que soit le calcul que vous voulez effectuer, il ne fonctionne que s'il y a une seule requête principale. Cela semble logique car vous pouvez référencer tous les CTE que vous voulez joindre comme n'importe quelle autre table. C'est l'un des avantages des CTE, alors profitez-en ! Deux CTE : L'un référençant l'autre Dans ce calcul un peu plus complexe, j'utilise à nouveau deux CTE. Cette fois, le second fait référence au premier. C'est la seule option si vous voulez qu'un CTE en référence un autre. Vous ne pouvez référencer que les CTE qui précèdent le CTE actuel et non les CTE qui suivent. Je vais les écrire pour calculer les ventes réelles en 2022 (à savoir, en janvier et février), budgétiser les ventes annuelles de 2022 en utilisant les ventes moyennes, et enfin trouver les ventes restant à réaliser en 2022. Je vous guiderai pas à pas dans le code ci-dessous, afin que vous compreniez ce qui se passe ici : WITH sales_per_car AS ( SELECT c.id, c.car_make, c.model, c.motor_type, c.year_of_production, AVG(cs.sales)::INT AS average_sales_2022 FROM cars c JOIN car_sales cs ON c.id = cs.cars_id WHERE c.year_of_production = 2022 GROUP BY c.id, c.car_make, c.model, c.motor_type, c.year_of_production ), budget AS ( SELECT *, average_sales_2022 * 12 AS annual_planned_sales_2022 FROM sales_per_car ) SELECT b.car_make, b.model, b.motor_type, b.year_of_production, SUM(cs.sales) AS actual_ytd_sales_2022, b.annual_planned_sales_2022, b.annual_planned_sales_2022 - SUM(cs.sales) AS remaining_annual_sales_2022 FROM budget b JOIN car_sales cs ON b.id = cs.cars_id GROUP BY b.car_make, b.model, b.motor_type, b.year_of_production, b.annual_planned_sales_2022; La syntaxe est la même que dans l'exemple précédent. Le CTE sales_per_car renvoie certaines colonnes de la table cars. J'utilise également la fonction AVG() pour calculer les ventes moyennes en 2022. Ce nombre est converti en un nombre entier parce que je parle de voitures et que je veux donc voir la moyenne sous la forme d'un nombre entier de voitures. Ce CTE me donne les ventes moyennes pour chaque modèle produit en 2022. Il permet également de comprendre pourquoi je sais que les ventes ne concernent que 2022 : les voitures produites en 2022 n'ont pas pu être vendues en 2021. C'est l'hypothèse retenue ici, du moins. Une virgule sépare ce CTE du second, qui commence par son nom, budget. Ce CTE fait maintenant référence au premier CTE comme n'importe quelle autre table. Vous pouvez le voir dans la clause FROM. J'utilise la colonne average_sales_2022 car il s'agit de la vente mensuelle moyenne réelle pour 2022. Disons que la méthode de budgétisation consiste à multiplier les ventes mensuelles moyennes de cette année par 12 pour obtenir les ventes annuelles prévues. C'est exactement ce que fait ce deuxième CTE, et c'est la raison pour laquelle il doit faire référence au premier CTE. La requête principale joint le CTE budget et la table car_sales. J'utilise cette requête pour trouver les ventes réelles par modèle en 2022. Ensuite, j'affiche la colonne annual_planned_sales_2022 à partir du deuxième CTE. Enfin, en calculant la différence entre ces deux colonnes, j'obtiens le nombre de ventes restant à réaliser pour le reste de l'année 2022. Voici le rapport que j'obtiens en exécutant la requête : car_makemodelmotor_typeyear_of_productionactual_ytd_sales_2022annual_planned_sales_2022remaining_annual_sales_2022 NissanJuke1.5 L HR15DE I4202214,05028,10414,054 NissanJuke1.6 L HR16DE I4202212,64925,29612,647 NissanMicra898 cc H4BT turbo I3202211,30022,59611,296 NissanMicra999 cc M281 I3202212,85925,71612,857 RenaultClio1.0 L H5Dt turbo I3202212,10724,21612,109 RenaultClio1.3 L H5Ht turbo I4202214,29728,59614,299 RenaultMeganeI3 12V TCe 115202212,47724,96012,483 RenaultMeganeI4 16V TCe 130202212,99725,99212,995 Deux CTEs : L'un des CTE est récursif. Je vais maintenant m'éloigner de ces données tout en restant dans le cadre de ces marques automobiles. Imaginons que Renault envisage trois investissements : acheter Jaguar pour 2 300 000 000, Volvo pour 1 548 470 000 ou Alfa Romeo pour 2 450 000 000. Elle envisage de le faire seule, avec Nissan, ou avec Nissan et Citroën. Cet exemple est parfait pour écrire deux CTE, dont l'un est récursif : WITH RECURSIVE company_purchase AS ( SELECT 2300000000 AS amount UNION SELECT 1548470000 AS amount UNION SELECT 2450000000 AS amount ), per_buyer AS ( SELECT 0 AS number_of_buyers, 0::DECIMAL AS purchase_amount, 0::DECIMAL AS amount_per_buyer UNION SELECT number_of_buyers + 1, amount, amount/(number_of_buyers + 1)::DECIMAL FROM company_purchase, per_buyer WHERE number_of_buyers <= 3) SELECT * FROM per_buyer ORDER BY purchase_amount, number_of_buyers; Chaque fois que vous voulez un CTE récursif, vous devez commencer à écrire des CTE avec WITH RECURSIVE. Vous annoncez toujours votre intention d'écrire un CTE récursif, que cette requête récursive soit le premier ou le second CTE. Dans ce cas, mon premier CTE est non récursif. J'utilise le company_purchase CTE pour créer différents investissements dans Jaguar, Volvo, ou Alfa Romeo. Ensuite vient la requête récursive. Le principe est le même : séparer les CTE par une virgule et commencer le deuxième CTE sans le mot clé WITH. Dans ce deuxième CTE, mon point de départ est l'absence totale d'investissement et d'acheteurs. Les valeurs seront partout égales à zéro. J'utilise ensuite la récursion, et la requête calcule le montant par acheteur pour un, deux ou trois investisseurs pour le premier investissement. La récursion répète ensuite le même calcul pour les deuxième et troisième investissements. Bien sûr, pour ce faire, je dois joindre la requête récursive à la requête non récursive. Enfin, la requête principale sélectionne toutes les données de l'ETC. per_buyer CTE, avec le résultat suivant : car_makemodelmotor_typeyear_of_productionactual_ytd_sales_2022annual_planned_sales_2022remaining_annual_sales_2022 NissanJuke1.5 L HR15DE I4202214,05028,10414,054 NissanJuke1.6 L HR16DE I4202212,64925,29612,647 NissanMicra898 cc H4BT turbo I3202211,30022,59611,296 NissanMicra999 cc M281 I3202212,85925,71612,857 RenaultClio1.0 L H5Dt turbo I3202212,10724,21612,109 RenaultClio1.3 L H5Ht turbo I4202214,29728,59614,299 RenaultMeganeI3 12V TCe 115202212,47724,96012,483 RenaultMeganeI4 16V TCe 130202212,99725,99212,995 Que me disent ces données ? Par exemple, si trois acheteurs (Renault, Nissan et Citroën) achètent Volvo pour 1 548 470 000, chaque entreprise doit investir 516 156 666,67. Vous trouverez d'autres exemples dans l'article sur les 5 principales questions d'entretien sur les CTE SQL et dans un autre article sur l'utilisation de deux CTE. Multipliez encore la puissance des CTEs Ces trois exemples ne sont que des exemples de ce que les CTE peuvent faire, et surtout de ce qu'ils peuvent faire si vous combinez plusieurs CTE de différentes manières. Ce concept n'est pas facile et demande beaucoup de pratique. Au lieu d'inventer vos propres données et scénarios, suivez notre cours interactif sur les expressions de tableaux communs! Il vous offre tout cela et élimine toutes les inquiétudes que vous avez sur la façon de pratiquer les CTE, avec plus de 100 exercices pratiques ! Tags: sql apprendre sql cte