[{"data":1,"prerenderedAt":884},["ShallowReactive",2],{"page-\u002Fsql\u002Fcreer-des-tables":3,"pieces-sql":841,"autour-\u002Fsql\u002Fcreer-des-tables":866,"prerequis-\u002Fsql\u002Fcreer-des-tables":871,"plan-sql":873},{"id":4,"title":5,"body":6,"description":813,"extension":814,"ligne":55,"meta":815,"motsCles":816,"navigation":819,"niveau":820,"path":821,"prerequis":822,"ressources":824,"seo":833,"sources":834,"stem":839,"__hash__":840},"docs\u002Fsql\u002F03.creer-des-tables.md","Créer des tables",{"type":7,"value":8,"toc":802},"minimark",[9,14,43,46,50,127,135,148,152,278,284,288,295,357,360,364,369,476,496,499,503,510,596,601,614,618,621,674,680,684,724,734,750,754,798],[10,11,13],"h2",{"id":12},"ce-que-tu-vas-apprendre","Ce que tu vas apprendre",[15,16,17,26,40],"ul",{},[18,19,20,21,25],"li",{},"Créer une table avec ",[22,23,24],"code",{},"CREATE TABLE"," et choisir le type de chaque colonne.",[18,27,28,29,32,33,32,36,39],{},"Protéger tes données avec des contraintes : clé primaire, ",[22,30,31],{},"NOT NULL",", ",[22,34,35],{},"UNIQUE",[22,37,38],{},"CHECK",".",[18,41,42],{},"Relier deux tables avec une clé étrangère.",[10,44,24],{"id":45},"create-table",[47,48,49],"p",{},"Commence par la table la plus simple de notre site :",[51,52,57],"pre",{"className":53,"code":54,"language":55,"meta":56,"style":56},"language-sql shiki shiki-themes github-light-default github-dark-default github-dark-default","CREATE TABLE categories (\n  id   bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,\n  nom  text NOT NULL UNIQUE\n);\n","sql","",[22,58,59,79,106,121],{"__ignoreMap":56},[60,61,64,68,71,75],"span",{"class":62,"line":63},"line",1,[60,65,67],{"class":66},"sOnC1","CREATE",[60,69,70],{"class":66}," TABLE",[60,72,74],{"class":73},"syCW7"," categories",[60,76,78],{"class":77},"scfrF"," (\n",[60,80,82,85,88,91,94,97,100,103],{"class":62,"line":81},2,[60,83,84],{"class":77},"  id   ",[60,86,87],{"class":66},"bigint",[60,89,90],{"class":66}," GENERATED",[60,92,93],{"class":66}," ALWAYS",[60,95,96],{"class":66}," AS",[60,98,99],{"class":66}," IDENTITY",[60,101,102],{"class":66}," PRIMARY KEY",[60,104,105],{"class":77},",\n",[60,107,109,112,115,118],{"class":62,"line":108},3,[60,110,111],{"class":77},"  nom  ",[60,113,114],{"class":66},"text",[60,116,117],{"class":66}," NOT NULL",[60,119,120],{"class":66}," UNIQUE\n",[60,122,124],{"class":62,"line":123},4,[60,125,126],{"class":77},");\n",[47,128,129,130,134],{},"Chaque ligne entre parenthèses décrit une colonne : son nom, son ",[131,132,133],"strong",{},"type"," (le genre de valeur qu'elle accepte), puis ses contraintes.",[47,136,137,140,141,144,145,39],{},[22,138,139],{},"GENERATED ALWAYS AS IDENTITY"," demande à PostgreSQL de numéroter lui-même les lignes : 1, 2, 3... Tu n'as plus à fournir l'",[22,142,143],{},"id"," dans tes ",[22,146,147],{},"INSERT",[10,149,151],{"id":150},"les-types-courants","Les types courants",[153,154,155,171],"table",{},[156,157,158],"thead",{},[159,160,161,165,168],"tr",{},[162,163,164],"th",{},"Type",[162,166,167],{},"Contenu",[162,169,170],{},"Exemple",[172,173,174,190,204,219,233,248,263],"tbody",{},[159,175,176,182,185],{},[177,178,179],"td",{},[22,180,181],{},"integer",[177,183,184],{},"nombre entier",[177,186,187],{},[22,188,189],{},"35",[159,191,192,196,199],{},[177,193,194],{},[22,195,87],{},[177,197,198],{},"grand nombre entier",[177,200,201],{},[22,202,203],{},"9000000000",[159,205,206,211,214],{},[177,207,208],{},[22,209,210],{},"numeric",[177,212,213],{},"nombre décimal exact",[177,215,216],{},[22,217,218],{},"1.5",[159,220,221,225,228],{},[177,222,223],{},[22,224,114],{},[177,226,227],{},"texte de longueur libre",[177,229,230],{},[22,231,232],{},"'Tarte'",[159,234,235,240,243],{},[177,236,237],{},[22,238,239],{},"boolean",[177,241,242],{},"vrai ou faux",[177,244,245],{},[22,246,247],{},"true",[159,249,250,255,258],{},[177,251,252],{},[22,253,254],{},"date",[177,256,257],{},"une date",[177,259,260],{},[22,261,262],{},"'2026-11-13'",[159,264,265,270,273],{},[177,266,267],{},[22,268,269],{},"timestamptz",[177,271,272],{},"date et heure avec fuseau horaire",[177,274,275],{},[22,276,277],{},"now()",[47,279,280,281,283],{},"Dans le doute pour un texte, ",[22,282,114],{}," convient très bien dans PostgreSQL.",[10,285,287],{"id":286},"les-contraintes","Les contraintes",[47,289,290,291,294],{},"Une ",[131,292,293],{},"contrainte"," est une règle que la base fait respecter. Si une ligne la viole, PostgreSQL refuse l'ajout ou la modification avec une erreur.",[153,296,297,307],{},[156,298,299],{},[159,300,301,304],{},[162,302,303],{},"Contrainte",[162,305,306],{},"Règle",[172,308,309,319,328,337,347],{},[159,310,311,316],{},[177,312,313],{},[22,314,315],{},"PRIMARY KEY",[177,317,318],{},"valeur unique et obligatoire, identifie la ligne",[159,320,321,325],{},[177,322,323],{},[22,324,31],{},[177,326,327],{},"la colonne ne peut pas rester vide",[159,329,330,334],{},[177,331,332],{},[22,333,35],{},[177,335,336],{},"pas deux fois la même valeur",[159,338,339,344],{},[177,340,341],{},[22,342,343],{},"CHECK (condition)",[177,345,346],{},"une condition sur la valeur",[159,348,349,354],{},[177,350,351],{},[22,352,353],{},"DEFAULT valeur",[177,355,356],{},"valeur prise si on n'en donne pas",[47,358,359],{},"La base est ton dernier rempart. Même si ton application oublie de vérifier une donnée, la contrainte la bloque.",[10,361,363],{"id":362},"une-clé-étrangère-pour-relier-les-tables","Une clé étrangère pour relier les tables",[47,365,366,367,39],{},"Une recette appartient à une catégorie. On ne recopie pas le nom de la catégorie dans chaque recette : on stocke son ",[22,368,143],{},[51,370,372],{"className":53,"code":371,"language":55,"meta":56,"style":56},"CREATE TABLE recettes (\n  id             bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,\n  titre          text NOT NULL,\n  temps_minutes  integer CHECK (temps_minutes > 0),\n  categorie_id   bigint REFERENCES categories (id),\n  cree_le        timestamptz NOT NULL DEFAULT now()\n);\n",[22,373,374,385,404,415,438,452,471],{"__ignoreMap":56},[60,375,376,378,380,383],{"class":62,"line":63},[60,377,67],{"class":66},[60,379,70],{"class":66},[60,381,382],{"class":73}," recettes",[60,384,78],{"class":77},[60,386,387,390,392,394,396,398,400,402],{"class":62,"line":81},[60,388,389],{"class":77},"  id             ",[60,391,87],{"class":66},[60,393,90],{"class":66},[60,395,93],{"class":66},[60,397,96],{"class":66},[60,399,99],{"class":66},[60,401,102],{"class":66},[60,403,105],{"class":77},[60,405,406,409,411,413],{"class":62,"line":108},[60,407,408],{"class":77},"  titre          ",[60,410,114],{"class":66},[60,412,117],{"class":66},[60,414,105],{"class":77},[60,416,417,420,422,425,428,431,435],{"class":62,"line":123},[60,418,419],{"class":77},"  temps_minutes  ",[60,421,181],{"class":66},[60,423,424],{"class":66}," CHECK",[60,426,427],{"class":77}," (temps_minutes ",[60,429,430],{"class":66},">",[60,432,434],{"class":433},"s5iOY"," 0",[60,436,437],{"class":77},"),\n",[60,439,441,444,446,449],{"class":62,"line":440},5,[60,442,443],{"class":77},"  categorie_id   ",[60,445,87],{"class":66},[60,447,448],{"class":66}," REFERENCES",[60,450,451],{"class":77}," categories (id),\n",[60,453,455,458,460,462,465,468],{"class":62,"line":454},6,[60,456,457],{"class":77},"  cree_le        ",[60,459,269],{"class":66},[60,461,117],{"class":66},[60,463,464],{"class":66}," DEFAULT",[60,466,467],{"class":66}," now",[60,469,470],{"class":77},"()\n",[60,472,474],{"class":62,"line":473},7,[60,475,126],{"class":77},[47,477,478,481,482,485,486,489,490,492,493,39],{},[22,479,480],{},"REFERENCES categories (id)"," crée une ",[131,483,484],{},"clé étrangère"," : la colonne ",[22,487,488],{},"categorie_id"," doit contenir un ",[22,491,143],{}," qui existe dans ",[22,494,495],{},"categories",[47,497,498],{},"Une catégorie inconnue est donc refusée. Et PostgreSQL empêche aussi de supprimer une catégorie encore utilisée par une recette.",[10,500,502],{"id":501},"une-table-pour-les-ingrédients","Une table pour les ingrédients",[47,504,505,506,509],{},"Une recette a plusieurs ingrédients. La table ",[22,507,508],{},"ingredients"," pointe vers sa recette :",[51,511,513],{"className":53,"code":512,"language":55,"meta":56,"style":56},"CREATE TABLE ingredients (\n  id          bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,\n  recette_id  bigint NOT NULL REFERENCES recettes (id) ON DELETE CASCADE,\n  nom         text NOT NULL,\n  quantite    numeric,\n  unite       text\n);\n",[22,514,515,526,545,564,575,584,592],{"__ignoreMap":56},[60,516,517,519,521,524],{"class":62,"line":63},[60,518,67],{"class":66},[60,520,70],{"class":66},[60,522,523],{"class":73}," ingredients",[60,525,78],{"class":77},[60,527,528,531,533,535,537,539,541,543],{"class":62,"line":81},[60,529,530],{"class":77},"  id          ",[60,532,87],{"class":66},[60,534,90],{"class":66},[60,536,93],{"class":66},[60,538,96],{"class":66},[60,540,99],{"class":66},[60,542,102],{"class":66},[60,544,105],{"class":77},[60,546,547,550,552,554,556,559,562],{"class":62,"line":108},[60,548,549],{"class":77},"  recette_id  ",[60,551,87],{"class":66},[60,553,117],{"class":66},[60,555,448],{"class":66},[60,557,558],{"class":77}," recettes (id) ",[60,560,561],{"class":66},"ON DELETE CASCADE",[60,563,105],{"class":77},[60,565,566,569,571,573],{"class":62,"line":123},[60,567,568],{"class":77},"  nom         ",[60,570,114],{"class":66},[60,572,117],{"class":66},[60,574,105],{"class":77},[60,576,577,580,582],{"class":62,"line":440},[60,578,579],{"class":77},"  quantite    ",[60,581,210],{"class":66},[60,583,105],{"class":77},[60,585,586,589],{"class":62,"line":454},[60,587,588],{"class":77},"  unite       ",[60,590,591],{"class":66},"text\n",[60,593,594],{"class":62,"line":473},[60,595,126],{"class":77},[47,597,598,600],{},[22,599,561],{}," précise ce qui arrive quand la recette est supprimée : ses ingrédients sont supprimés avec elle. Sans cette option, la suppression serait refusée tant qu'il reste des ingrédients.",[602,603,604],"note",{},[47,605,606,607,610,611,613],{},"Le lien entre ",[22,608,609],{},"recettes"," et ",[22,612,508],{}," est de type « un vers plusieurs » : une recette, plusieurs ingrédients. La clé étrangère se place toujours du côté « plusieurs ».",[10,615,617],{"id":616},"tester-les-contraintes","Tester les contraintes",[47,619,620],{},"Essaie ces deux requêtes, elles échouent volontairement :",[51,622,624],{"className":53,"code":623,"language":55,"meta":56,"style":56},"INSERT INTO recettes (titre, temps_minutes) VALUES ('Soupe', -5);\nINSERT INTO recettes (titre, categorie_id) VALUES ('Soupe', 999);\n",[22,625,626,654],{"__ignoreMap":56},[60,627,628,631,634,637,640,644,646,649,652],{"class":62,"line":63},[60,629,630],{"class":66},"INSERT INTO",[60,632,633],{"class":77}," recettes (titre, temps_minutes) ",[60,635,636],{"class":66},"VALUES",[60,638,639],{"class":77}," (",[60,641,643],{"class":642},"shWOn","'Soupe'",[60,645,32],{"class":77},[60,647,648],{"class":66},"-",[60,650,651],{"class":433},"5",[60,653,126],{"class":77},[60,655,656,658,661,663,665,667,669,672],{"class":62,"line":81},[60,657,630],{"class":66},[60,659,660],{"class":77}," recettes (titre, categorie_id) ",[60,662,636],{"class":66},[60,664,639],{"class":77},[60,666,643],{"class":642},[60,668,32],{"class":77},[60,670,671],{"class":433},"999",[60,673,126],{"class":77},[47,675,676,677,679],{},"La première viole le ",[22,678,38],{}," (durée négative). La seconde viole la clé étrangère (la catégorie 999 n'existe pas). Lis le message d'erreur : il nomme la contrainte en cause.",[10,681,683],{"id":682},"modifier-ou-supprimer-une-table","Modifier ou supprimer une table",[51,685,687],{"className":53,"code":686,"language":55,"meta":56,"style":56},"ALTER TABLE recettes ADD COLUMN vegetarienne boolean NOT NULL DEFAULT false;\nDROP TABLE ingredients;\n",[22,688,689,714],{"__ignoreMap":56},[60,690,691,694,696,699,702,705,707,709,711],{"class":62,"line":63},[60,692,693],{"class":66},"ALTER",[60,695,70],{"class":66},[60,697,698],{"class":77}," recettes ",[60,700,701],{"class":66},"ADD",[60,703,704],{"class":77}," COLUMN vegetarienne ",[60,706,239],{"class":66},[60,708,117],{"class":66},[60,710,464],{"class":66},[60,712,713],{"class":77}," false;\n",[60,715,716,719,721],{"class":62,"line":81},[60,717,718],{"class":66},"DROP",[60,720,70],{"class":66},[60,722,723],{"class":77}," ingredients;\n",[47,725,726,729,730,733],{},[22,727,728],{},"ALTER TABLE"," change la structure d'une table existante. ",[22,731,732],{},"DROP TABLE"," la supprime avec toutes ses données.",[735,736,737],"warning",{},[47,738,739,741,742,745,746,749],{},[22,740,732],{}," est définitif, comme un ",[22,743,744],{},"DELETE"," sans ",[22,747,748],{},"WHERE",". Vérifie le nom de la table avant d'exécuter la commande.",[10,751,753],{"id":752},"à-retenir","À retenir",[15,755,756,761,770,783,790],{},[18,757,758,760],{},[22,759,24],{}," décrit les colonnes, leur type et leurs contraintes.",[18,762,763,766,767,769],{},[22,764,765],{},"GENERATED ALWAYS AS IDENTITY PRIMARY KEY"," donne un ",[22,768,143],{}," numéroté automatiquement.",[18,771,772,773,32,775,32,777,32,779,782],{},"Les contraintes (",[22,774,31],{},[22,776,35],{},[22,778,38],{},[22,780,781],{},"DEFAULT",") font respecter des règles par la base elle-même.",[18,784,785,786,789],{},"Une clé étrangère (",[22,787,788],{},"REFERENCES",") relie deux tables et interdit les liens vers une ligne inexistante.",[18,791,792,794,795,797],{},[22,793,561],{}," supprime les lignes liées ; ",[22,796,732],{}," supprime toute la table, sans retour.",[799,800,801],"style",{},"html pre.shiki code .sOnC1, html code.shiki .sOnC1{--shiki-light:#CF222E;--shiki-default:#FF7B72;--shiki-dark:#FF7B72}html pre.shiki code .syCW7, html code.shiki .syCW7{--shiki-light:#8250DF;--shiki-default:#D2A8FF;--shiki-dark:#D2A8FF}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 .s5iOY, html code.shiki .s5iOY{--shiki-light:#0550AE;--shiki-default:#79C0FF;--shiki-dark:#79C0FF}html pre.shiki code .shWOn, html code.shiki .shWOn{--shiki-light:#0A3069;--shiki-default:#A5D6FF;--shiki-dark:#A5D6FF}",{"title":56,"searchDepth":81,"depth":108,"links":803},[804,805,806,807,808,809,810,811,812],{"id":12,"depth":81,"text":13},{"id":45,"depth":81,"text":24},{"id":150,"depth":81,"text":151},{"id":286,"depth":81,"text":287},{"id":362,"depth":81,"text":363},{"id":501,"depth":81,"text":502},{"id":616,"depth":81,"text":617},{"id":682,"depth":81,"text":683},{"id":752,"depth":81,"text":753},"Définir ses propres tables avec CREATE TABLE, choisir les types, poser des contraintes et relier les tables par des clés étrangères.","md",{},[24,817,315,31,35,38,484,788,818,732],"types de données","IDENTITY",true,"debutant","\u002Fsql\u002Fcreer-des-tables",[823],"\u002Fsql\u002Fmodifier-les-donnees",[825,829],{"nom":826,"url":827,"type":828},"Documentation PostgreSQL en français, « Contraintes »","https:\u002F\u002Fdocs.postgresql.fr\u002Fcurrent\u002Fddl-constraints.html","doc",{"nom":830,"url":831,"type":832},"SQL.sh, cours et tutoriels sur le langage SQL","https:\u002F\u002Fsql.sh\u002F","cours",{"title":5,"description":813},[835,836],{"nom":826,"url":827},{"nom":837,"url":838},"PostgreSQL, colonnes d'identité (en anglais)","https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002Fcurrent\u002Fddl-identity-columns.html","sql\u002F03.creer-des-tables","wIUkdQD5lfVhoIUHED_PQ6pKizz8zhTEtUdLX91jvUM",[842,846,849,850,854,858,862],{"path":843,"title":844,"stem":845},"\u002Fsql\u002Fbase-relationnelle","La base relationnelle et SELECT","sql\u002F01.base-relationnelle",{"path":823,"title":847,"stem":848},"Ajouter, modifier et supprimer des lignes","sql\u002F02.modifier-les-donnees",{"path":821,"title":5,"stem":839},{"path":851,"title":852,"stem":853},"\u002Fsql\u002Fjointures","Les jointures","sql\u002F04.jointures",{"path":855,"title":856,"stem":857},"\u002Fsql\u002Fagregats-et-index","Agrégats et index","sql\u002F05.agregats-et-index",{"path":859,"title":860,"stem":861},"\u002Fsql\u002Ftransactions-et-injection","Transactions et injection SQL","sql\u002F06.transactions-et-injection",{"path":863,"title":864,"stem":865},"\u002Fsql","SQL","sql\u002Findex",[867,869],{"title":847,"path":823,"stem":848,"description":868,"children":-1},"Écrire dans une base avec INSERT, UPDATE et DELETE, et comprendre pourquoi oublier le WHERE peut tout effacer.",{"title":852,"path":851,"stem":853,"description":870,"children":-1},"Combiner plusieurs tables dans une seule requête avec INNER JOIN et LEFT JOIN, et utiliser des alias pour garder des requêtes lisibles.",[872],{"path":823,"title":847,"ligne":55},[874,875,876,877,879,880,882],{"path":843,"title":844,"niveau":820,"stem":845},{"path":823,"title":847,"niveau":820,"stem":848},{"path":821,"title":5,"niveau":820,"stem":839},{"path":851,"title":852,"niveau":878,"stem":853},"intermediaire",{"path":855,"title":856,"niveau":878,"stem":857},{"path":859,"title":860,"niveau":881,"stem":861},"avance",{"path":863,"title":864,"niveau":883,"stem":865},"memo",1794583462976]