[{"data":1,"prerenderedAt":928},["ShallowReactive",2],{"page-\u002Fsql\u002Fjointures":3,"pieces-sql":885,"autour-\u002Fsql\u002Fjointures":910,"prerequis-\u002Fsql\u002Fjointures":915,"plan-sql":917},{"id":4,"title":5,"body":6,"description":856,"extension":857,"ligne":130,"meta":858,"motsCles":859,"navigation":863,"niveau":864,"path":865,"prerequis":866,"ressources":868,"seo":877,"sources":878,"stem":883,"__hash__":884},"docs\u002Fsql\u002F04.jointures.md","Les jointures",{"type":7,"value":8,"toc":845},"minimark",[9,14,36,40,52,105,122,125,201,204,238,247,256,260,267,372,384,387,403,468,471,509,514,518,521,591,604,608,650,658,662,668,776,784,797,809,813,841],[10,11,13],"h2",{"id":12},"ce-que-tu-vas-apprendre","Ce que tu vas apprendre",[15,16,17,21,33],"ul",{},[18,19,20],"li",{},"Pourquoi on répartit les données dans plusieurs tables, puis comment les recombiner.",[18,22,23,24,28,29,32],{},"Utiliser ",[25,26,27],"code",{},"INNER JOIN"," et ",[25,30,31],{},"LEFT JOIN",".",[18,34,35],{},"Écrire des requêtes lisibles avec des alias.",[10,37,39],{"id":38},"le-problème","Le problème",[41,42,43,44,47,48,51],"p",{},"La table ",[25,45,46],{},"recettes"," contient seulement un ",[25,49,50],{},"categorie_id",". Si tu lis cette table, tu vois des numéros, pas des noms :",[53,54,55,70],"table",{},[56,57,58],"thead",{},[59,60,61,65,68],"tr",{},[62,63,64],"th",{},"id",[62,66,67],{},"titre",[62,69,50],{},[71,72,73,84,94],"tbody",{},[59,74,75,79,82],{},[76,77,78],"td",{},"1",[76,80,81],{},"Velouté de potimarron",[76,83,78],{},[59,85,86,89,92],{},[76,87,88],{},"2",[76,90,91],{},"Gratin dauphinois",[76,93,88],{},[59,95,96,99,102],{},[76,97,98],{},"4",[76,100,101],{},"Tarte aux pommes",[76,103,104],{},"3",[41,106,107,108,111,112,116,117,121],{},"Le nom « Desserts » est dans la table ",[25,109,110],{},"categories",". Une ",[113,114,115],"strong",{},"jointure"," (",[118,119,120],"em",{},"join",") associe les lignes de deux tables grâce à une colonne commune.",[10,123,27],{"id":124},"inner-join",[126,127,132],"pre",{"className":128,"code":129,"language":130,"meta":131,"style":131},"language-sql shiki shiki-themes github-light-default github-dark-default github-dark-default","SELECT recettes.titre, categories.nom\nFROM recettes\nINNER JOIN categories ON categories.id = recettes.categorie_id;\n","sql","",[25,133,134,162,171],{"__ignoreMap":131},[135,136,139,143,147,150,152,155,157,159],"span",{"class":137,"line":138},"line",1,[135,140,142],{"class":141},"sOnC1","SELECT",[135,144,146],{"class":145},"s5iOY"," recettes",[135,148,32],{"class":149},"scfrF",[135,151,67],{"class":145},[135,153,154],{"class":149},", ",[135,156,110],{"class":145},[135,158,32],{"class":149},[135,160,161],{"class":145},"nom\n",[135,163,165,168],{"class":137,"line":164},2,[135,166,167],{"class":141},"FROM",[135,169,170],{"class":149}," recettes\n",[135,172,174,176,179,182,185,187,189,192,194,196,198],{"class":137,"line":173},3,[135,175,27],{"class":141},[135,177,178],{"class":149}," categories ",[135,180,181],{"class":141},"ON",[135,183,184],{"class":145}," categories",[135,186,32],{"class":149},[135,188,64],{"class":145},[135,190,191],{"class":141}," =",[135,193,146],{"class":145},[135,195,32],{"class":149},[135,197,50],{"class":145},[135,199,200],{"class":149},";\n",[41,202,203],{},"Résultat (extrait, une ligne par catégorie pour faire court) :",[53,205,206,215],{},[56,207,208],{},[59,209,210,212],{},[62,211,67],{},[62,213,214],{},"nom",[71,216,217,224,231],{},[59,218,219,221],{},[76,220,81],{},[76,222,223],{},"Entrées",[59,225,226,228],{},[76,227,91],{},[76,229,230],{},"Plats",[59,232,233,235],{},[76,234,101],{},[76,236,237],{},"Desserts",[41,239,240,241,243,244,246],{},"Après ",[25,242,181],{},", tu écris la condition qui relie les lignes. PostgreSQL associe chaque recette à la catégorie dont l'",[25,245,64],{}," correspond.",[41,248,249,251,252,255],{},[25,250,27],{}," ne garde que les lignes qui ont une correspondance des deux côtés. On peut écrire ",[25,253,254],{},"JOIN"," tout court : c'est la même chose.",[10,257,259],{"id":258},"les-alias","Les alias",[41,261,262,263,266],{},"Les noms de table répétés alourdissent la requête. Donne-leur un ",[113,264,265],{},"alias",", un surnom court :",[126,268,270],{"className":128,"code":269,"language":130,"meta":131,"style":131},"SELECT r.titre, c.nom AS categorie\nFROM recettes AS r\nJOIN categories AS c ON c.id = r.categorie_id\nWHERE c.nom = 'Desserts'\nORDER BY r.titre;\n",[25,271,272,298,311,340,358],{"__ignoreMap":131},[135,273,274,276,279,281,283,285,288,290,292,295],{"class":137,"line":138},[135,275,142],{"class":141},[135,277,278],{"class":145}," r",[135,280,32],{"class":149},[135,282,67],{"class":145},[135,284,154],{"class":149},[135,286,287],{"class":145},"c",[135,289,32],{"class":149},[135,291,214],{"class":145},[135,293,294],{"class":141}," AS",[135,296,297],{"class":149}," categorie\n",[135,299,300,302,305,308],{"class":137,"line":164},[135,301,167],{"class":141},[135,303,304],{"class":149}," recettes ",[135,306,307],{"class":141},"AS",[135,309,310],{"class":149}," r\n",[135,312,313,315,317,319,322,324,327,329,331,333,335,337],{"class":137,"line":173},[135,314,254],{"class":141},[135,316,178],{"class":149},[135,318,307],{"class":141},[135,320,321],{"class":149}," c ",[135,323,181],{"class":141},[135,325,326],{"class":145}," c",[135,328,32],{"class":149},[135,330,64],{"class":145},[135,332,191],{"class":141},[135,334,278],{"class":145},[135,336,32],{"class":149},[135,338,339],{"class":145},"categorie_id\n",[135,341,343,346,348,350,352,354],{"class":137,"line":342},4,[135,344,345],{"class":141},"WHERE",[135,347,326],{"class":145},[135,349,32],{"class":149},[135,351,214],{"class":145},[135,353,191],{"class":141},[135,355,357],{"class":356},"shWOn"," 'Desserts'\n",[135,359,361,364,366,368,370],{"class":137,"line":360},5,[135,362,363],{"class":141},"ORDER BY",[135,365,278],{"class":145},[135,367,32],{"class":149},[135,369,67],{"class":145},[135,371,200],{"class":149},[41,373,374,377,378,380,381,383],{},[25,375,376],{},"AS categorie"," renomme aussi la colonne du résultat. Le ",[25,379,345],{}," et le ",[25,382,363],{}," s'appliquent comme avant, sur les colonnes des deux tables.",[10,385,31],{"id":386},"left-join",[41,388,389,390,392,393,395,396,399,400,402],{},"Que se passe-t-il pour une catégorie sans recette, comme « Boissons » ? Un ",[25,391,27],{}," l'oublie. Un ",[25,394,31],{}," garde toutes les lignes de la table de ",[113,397,398],{},"gauche",", celle citée après ",[25,401,167],{}," :",[126,404,406],{"className":128,"code":405,"language":130,"meta":131,"style":131},"SELECT c.nom, r.titre\nFROM categories AS c\nLEFT JOIN recettes AS r ON r.categorie_id = c.id;\n",[25,407,408,428,439],{"__ignoreMap":131},[135,409,410,412,414,416,418,420,423,425],{"class":137,"line":138},[135,411,142],{"class":141},[135,413,326],{"class":145},[135,415,32],{"class":149},[135,417,214],{"class":145},[135,419,154],{"class":149},[135,421,422],{"class":145},"r",[135,424,32],{"class":149},[135,426,427],{"class":145},"titre\n",[135,429,430,432,434,436],{"class":137,"line":164},[135,431,167],{"class":141},[135,433,178],{"class":149},[135,435,307],{"class":141},[135,437,438],{"class":149}," c\n",[135,440,441,443,445,447,450,452,454,456,458,460,462,464,466],{"class":137,"line":173},[135,442,31],{"class":141},[135,444,304],{"class":149},[135,446,307],{"class":141},[135,448,449],{"class":149}," r ",[135,451,181],{"class":141},[135,453,278],{"class":145},[135,455,32],{"class":149},[135,457,50],{"class":145},[135,459,191],{"class":141},[135,461,326],{"class":145},[135,463,32],{"class":149},[135,465,64],{"class":145},[135,467,200],{"class":149},[41,469,470],{},"Résultat (extrait) :",[53,472,473,481],{},[56,474,475],{},[59,476,477,479],{},[62,478,214],{},[62,480,67],{},[71,482,483,489,495,501],{},[59,484,485,487],{},[76,486,223],{},[76,488,81],{},[59,490,491,493],{},[76,492,230],{},[76,494,91],{},[59,496,497,499],{},[76,498,237],{},[76,500,101],{},[59,502,503,506],{},[76,504,505],{},"Boissons",[76,507,508],{},"NULL",[41,510,511,512,32],{},"Quand aucune recette ne correspond, les colonnes de droite valent ",[25,513,508],{},[10,515,517],{"id":516},"trouver-ce-qui-na-pas-de-correspondance","Trouver ce qui n'a pas de correspondance",[41,519,520],{},"Cette propriété sert à repérer les lignes orphelines. Voici les catégories sans aucune recette :",[126,522,524],{"className":128,"code":523,"language":130,"meta":131,"style":131},"SELECT c.nom\nFROM categories AS c\nLEFT JOIN recettes AS r ON r.categorie_id = c.id\nWHERE r.id IS NULL;\n",[25,525,526,536,546,573],{"__ignoreMap":131},[135,527,528,530,532,534],{"class":137,"line":138},[135,529,142],{"class":141},[135,531,326],{"class":145},[135,533,32],{"class":149},[135,535,161],{"class":145},[135,537,538,540,542,544],{"class":137,"line":164},[135,539,167],{"class":141},[135,541,178],{"class":149},[135,543,307],{"class":141},[135,545,438],{"class":149},[135,547,548,550,552,554,556,558,560,562,564,566,568,570],{"class":137,"line":173},[135,549,31],{"class":141},[135,551,304],{"class":149},[135,553,307],{"class":141},[135,555,449],{"class":149},[135,557,181],{"class":141},[135,559,278],{"class":145},[135,561,32],{"class":149},[135,563,50],{"class":145},[135,565,191],{"class":141},[135,567,326],{"class":145},[135,569,32],{"class":149},[135,571,572],{"class":145},"id\n",[135,574,575,577,579,581,583,586,589],{"class":137,"line":342},[135,576,345],{"class":141},[135,578,278],{"class":145},[135,580,32],{"class":149},[135,582,64],{"class":145},[135,584,585],{"class":141}," IS",[135,587,588],{"class":141}," NULL",[135,590,200],{"class":149},[41,592,593,594,596,597,600,601,32],{},"On garde les lignes où le côté droit est vide. Rappelle-toi qu'un ",[25,595,508],{}," se teste avec ",[25,598,599],{},"IS NULL",", jamais avec ",[25,602,603],{},"=",[10,605,607],{"id":606},"quel-type-de-jointure-choisir","Quel type de jointure choisir ?",[53,609,610,620],{},[56,611,612],{},[59,613,614,617],{},[62,615,616],{},"Besoin",[62,618,619],{},"Jointure",[71,621,622,631,640],{},[59,623,624,627],{},[76,625,626],{},"Seulement les lignes liées des deux côtés",[76,628,629],{},[25,630,27],{},[59,632,633,636],{},[76,634,635],{},"Toute la table de gauche, liée ou non",[76,637,638],{},[25,639,31],{},[59,641,642,645],{},[76,643,644],{},"Toute la table de droite, liée ou non",[76,646,647],{},[25,648,649],{},"RIGHT JOIN",[41,651,652,654,655,657],{},[25,653,649],{}," est l'image miroir de ",[25,656,31],{},". On l'utilise rarement : il suffit d'échanger l'ordre des tables.",[10,659,661],{"id":660},"joindre-trois-tables","Joindre trois tables",[41,663,664,665,667],{},"Tu enchaînes les ",[25,666,254],{},". Voici chaque ingrédient avec sa recette et sa catégorie :",[126,669,671],{"className":128,"code":670,"language":130,"meta":131,"style":131},"SELECT r.titre, c.nom AS categorie, i.nom AS ingredient\nFROM ingredients AS i\nJOIN recettes AS r ON r.id = i.recette_id\nJOIN categories AS c ON c.id = r.categorie_id;\n",[25,672,673,708,720,748],{"__ignoreMap":131},[135,674,675,677,679,681,683,685,687,689,691,693,696,699,701,703,705],{"class":137,"line":138},[135,676,142],{"class":141},[135,678,278],{"class":145},[135,680,32],{"class":149},[135,682,67],{"class":145},[135,684,154],{"class":149},[135,686,287],{"class":145},[135,688,32],{"class":149},[135,690,214],{"class":145},[135,692,294],{"class":141},[135,694,695],{"class":149}," categorie, ",[135,697,698],{"class":145},"i",[135,700,32],{"class":149},[135,702,214],{"class":145},[135,704,294],{"class":141},[135,706,707],{"class":149}," ingredient\n",[135,709,710,712,715,717],{"class":137,"line":164},[135,711,167],{"class":141},[135,713,714],{"class":149}," ingredients ",[135,716,307],{"class":141},[135,718,719],{"class":149}," i\n",[135,721,722,724,726,728,730,732,734,736,738,740,743,745],{"class":137,"line":173},[135,723,254],{"class":141},[135,725,304],{"class":149},[135,727,307],{"class":141},[135,729,449],{"class":149},[135,731,181],{"class":141},[135,733,278],{"class":145},[135,735,32],{"class":149},[135,737,64],{"class":145},[135,739,191],{"class":141},[135,741,742],{"class":145}," i",[135,744,32],{"class":149},[135,746,747],{"class":145},"recette_id\n",[135,749,750,752,754,756,758,760,762,764,766,768,770,772,774],{"class":137,"line":342},[135,751,254],{"class":141},[135,753,178],{"class":149},[135,755,307],{"class":141},[135,757,321],{"class":149},[135,759,181],{"class":141},[135,761,326],{"class":145},[135,763,32],{"class":149},[135,765,64],{"class":145},[135,767,191],{"class":141},[135,769,278],{"class":145},[135,771,32],{"class":149},[135,773,50],{"class":145},[135,775,200],{"class":149},[41,777,778,779,781,782,32],{},"Chaque ",[25,780,254],{}," ajoute une table, avec sa propre condition ",[25,783,181],{},[785,786,787],"warning",{},[41,788,789,790,792,793,796],{},"N'oublie jamais la condition ",[25,791,181],{},". Sans elle (avec une virgule entre les tables, ou avec ",[25,794,795],{},"CROSS JOIN","), PostgreSQL associe chaque ligne de la première table à chaque ligne de la seconde. Avec 1 000 lignes de chaque côté, tu obtiens 1 000 000 de lignes.",[798,799,800],"tip",{},[41,801,802,803,805,806,808],{},"Quand deux tables ont une colonne du même nom, comme ",[25,804,64],{}," ou ",[25,807,214],{},", préfixe-la par l'alias de sa table. Sinon PostgreSQL répond que la colonne est « ambiguë ».",[10,810,812],{"id":811},"à-retenir","À retenir",[15,814,815,818,824,832,838],{},[18,816,817],{},"Une jointure recombine des tables grâce à une colonne commune, en général une clé étrangère.",[18,819,820,823],{},[25,821,822],{},"INNER JOIN ... ON"," garde seulement les lignes qui se correspondent des deux côtés.",[18,825,826,828,829,831],{},[25,827,31],{}," garde toutes les lignes de gauche et met ",[25,830,508],{}," à droite quand rien ne correspond.",[18,833,834,837],{},[25,835,836],{},"LEFT JOIN ... WHERE droite.id IS NULL"," trouve les lignes sans correspondance.",[18,839,840],{},"Utilise des alias courts et préfixe les colonnes pour lever toute ambiguïté.",[842,843,844],"style",{},"html pre.shiki code .sOnC1, html code.shiki .sOnC1{--shiki-light:#CF222E;--shiki-default:#FF7B72;--shiki-dark:#FF7B72}html pre.shiki code .s5iOY, html code.shiki .s5iOY{--shiki-light:#0550AE;--shiki-default:#79C0FF;--shiki-dark:#79C0FF}html pre.shiki code .scfrF, html code.shiki .scfrF{--shiki-light:#1F2328;--shiki-default:#E6EDF3;--shiki-dark:#E6EDF3}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .shWOn, html code.shiki .shWOn{--shiki-light:#0A3069;--shiki-default:#A5D6FF;--shiki-dark:#A5D6FF}",{"title":131,"searchDepth":164,"depth":173,"links":846},[847,848,849,850,851,852,853,854,855],{"id":12,"depth":164,"text":13},{"id":38,"depth":164,"text":39},{"id":124,"depth":164,"text":27},{"id":258,"depth":164,"text":259},{"id":386,"depth":164,"text":31},{"id":516,"depth":164,"text":517},{"id":606,"depth":164,"text":607},{"id":660,"depth":164,"text":661},{"id":811,"depth":164,"text":812},"Combiner plusieurs tables dans une seule requête avec INNER JOIN et LEFT JOIN, et utiliser des alias pour garder des requêtes lisibles.","md",{},[254,27,31,181,265,860,861,862],"clé étrangère",null,"produit cartésien",true,"intermediaire","\u002Fsql\u002Fjointures",[867],"\u002Fsql\u002Fcreer-des-tables",[869,873],{"nom":870,"url":871,"type":872},"Documentation PostgreSQL en français, « Jointures entre les tables »","https:\u002F\u002Fdocs.postgresql.fr\u002Fcurrent\u002Ftutorial-join.html","doc",{"nom":874,"url":875,"type":876},"SQL.sh, les jointures SQL","https:\u002F\u002Fsql.sh\u002Fcours\u002Fjointures","cours",{"title":5,"description":856},[879,880],{"nom":870,"url":871},{"nom":881,"url":882},"Documentation PostgreSQL (en anglais)","https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002Fcurrent\u002Ftutorial-join.html","sql\u002F04.jointures","TN1jXNIy6XnPR1TCChH71BRITQocVLN0gU1WmsgnCE8",[886,890,894,897,898,902,906],{"path":887,"title":888,"stem":889},"\u002Fsql\u002Fbase-relationnelle","La base relationnelle et SELECT","sql\u002F01.base-relationnelle",{"path":891,"title":892,"stem":893},"\u002Fsql\u002Fmodifier-les-donnees","Ajouter, modifier et supprimer des lignes","sql\u002F02.modifier-les-donnees",{"path":867,"title":895,"stem":896},"Créer des tables","sql\u002F03.creer-des-tables",{"path":865,"title":5,"stem":883},{"path":899,"title":900,"stem":901},"\u002Fsql\u002Fagregats-et-index","Agrégats et index","sql\u002F05.agregats-et-index",{"path":903,"title":904,"stem":905},"\u002Fsql\u002Ftransactions-et-injection","Transactions et injection SQL","sql\u002F06.transactions-et-injection",{"path":907,"title":908,"stem":909},"\u002Fsql","SQL","sql\u002Findex",[911,913],{"title":895,"path":867,"stem":896,"description":912,"children":-1},"Définir ses propres tables avec CREATE TABLE, choisir les types, poser des contraintes et relier les tables par des clés étrangères.",{"title":900,"path":899,"stem":901,"description":914,"children":-1},"Calculer des totaux et des moyennes avec COUNT, SUM, AVG, GROUP BY et HAVING, puis accélérer les recherches avec un index.",[916],{"path":867,"title":895,"ligne":130},[918,920,921,922,923,924,926],{"path":887,"title":888,"niveau":919,"stem":889},"debutant",{"path":891,"title":892,"niveau":919,"stem":893},{"path":867,"title":895,"niveau":919,"stem":896},{"path":865,"title":5,"niveau":864,"stem":883},{"path":899,"title":900,"niveau":864,"stem":901},{"path":903,"title":904,"niveau":925,"stem":905},"avance",{"path":907,"title":908,"niveau":927,"stem":909},"memo",1794583463132]