SQL Poche Pour les Nuls, 3e (French Edition)informatique-loiret.fr/Tuto/databases/SQL pour les...
Transcript of SQL Poche Pour les Nuls, 3e (French Edition)informatique-loiret.fr/Tuto/databases/SQL pour les...
SQL
Nouvelleédition
AllenG.Taylor
SQLpourlesNuls(nouvelleédition)Titredel’éditionoriginale:SQLForDummies®,8thEditionPourlesNulsestunemarquedéposéedeWileyPublishing,Inc.ForDummiesestunemarquedéposéedeWileyPublishing,Inc.
CollectiondirigéeparJean-PierreCanoTraduction:Jean-PaulDuplanetStéphaneBontempsMiseenpage:maged
EditionfrançaisepubliéeenaccordavecWileyPublishing,Inc.©ÉditionsFirst,undépartementd’Édi8,2017ÉditionsFirst,undépartementd’Édi812avenued’Italie75013ParisTél.:0144160900Fax:0144160901E-mail:[email protected]:www.editionsfirst.frISBN:978-2-412-02377-8ISBNnumérique:9782412026458Dépôtlégal:1ertrimestre2017Cetteœuvreestprotégéeparledroitd’auteuretstrictementréservéeàl’usageprivéduclient.Toutereproductionoudiffusionauprofitdetiers,àtitregratuitouonéreux,detout ou partie de cette œuvre est strictement interdite et constitue une contrefaçonprévue par les articles L 335-2 et suivants du Code de la propriété intellectuelle.L’éditeur se réserve le droit de poursuivre toute atteinte à ses droits de propriétéintellectuelledevantlesjuridictionscivilesoupénales.
CelivrenumériqueaétéconvertiinitialementauformatEPUBparIsakowww.isako.comàpartirdel'éditionpapierdumêmeouvrage.
B
Introduction
ienvenue dans lemondedes bases de données et de son langageSQL(langage structuré de requêtes). Il existe de nombreux systèmes degestiondebasesdedonnées(SGBD)pourdenombreusesplates-formes
matérielles.Cesproduitspeuventparfoisêtretrèsdifférents,maistousceuxqui sont dignes de ce nom partagent quelque chose en commun : ilspermettentl’accèsetlamanipulationdesdonnéesviaSQL.ConnaîtreSQL,c’est pouvoir créer des bases de données relationnelles et en extrairen’importequelleinformation.
AusujetdecelivreLes systèmesdegestiondebasededonnées sont au cœurdenombreusesorganisations.Lesgenspensentsouventque lacréationet l’administrationde ces systèmes sont des tâches très complexes, réservées à destechnogourous spécialisés en bases de données qui disposent deconnaissancesque le simplemortelnepourrait espérer acquérir.Ce livrebalaiecemythe.Voicicequevousytrouverez:
» Découvrirlesnotionsélémentairesdesbasesdedonnées.
» ComprendrecommentunSGBDeststructuré.
» DécouvrirlesfonctionnalitésmajeuresdeSQL.
» Créerunebasededonnées.
» Protégerunebasededonnées.
» Travaillersurlesdonnéesd’unebasededonnées.
» Déterminercommentextrairel’informationquevous
souhaitezd’unebasededonnées.
L’objectifdecelivreestdevousapprendreàcréerdesbasesdedonnéesrelationnellesetàenextrairedesinformationsutilesàl’aidedeSQL.SQLestunlangagestandardinternationalutilisédanslemondeentierpourcréeret administrer des bases de données. Cette édition traite de la dernièreversiondustandard,SQL:2011.
Celivrenevousapprendrapascommentproduireunmodèlededonnées.Jesupposequevous-mêmeouquelqu’und’autrel’aurontdéjàfait.Cependant,cet ouvrage vous montrera comment implémenter ce modèle à l’aide deSQL. Si vous pensez que votre modèle de données n’est pas bon, vousdevez absolument le repenser avant de construire la base de donnéescorrespondante.Plustôtvousdétecterezetcorrigerezcetypedeproblèmedeconception,moinsilvousencoûtera.
Quidevraitlirecelivre?ConnaîtreSQLvousrendraservicechaquefoisquevousdevrezstockerourécupérer des données dans un SGBD. Vous n’avez pas besoin d’êtreprogrammeurpourutiliserSQL,pasplusquevousn’avezàconnaîtredeslangages tels que le COBOL, le C ou le Basic. La syntaxe de SQL estentièrementenanglais(etnonenfrançais,désolé).
Si vous êtes programmeur, vous pourrez incorporer SQL dans vosprogrammes pour manipuler plus facilement des données. Ce livre vousmontreracommentprocéderafind’intégrerdansvosapplicationslesrichesetpuissantsoutilsqu’offrecelangage.
IcônesutiliséesdanscelivreCeconseilvouspermetdegagnerdutempsetdeleverdesdoutes.
Souvenez-vousde l’information signaléepar cette icône carvouspourrezenavoirbesoinultérieurement.
Tenez compte du conseil qui Figure à côté de cette icône. Il peut vousgarantircontredesproblèmesmajeurs.Ignorez-leàvosrisquesetpérils.
Cette icône vous signale la présence de détails techniques qu’il estintéressantmaispasindispensabledeconnaître.
PourcommencerLesbasesdedonnées sont lesmeilleursoutilsquiaient été inventéspourconserver la trace des données qui vous importent.Comprendre commentellesfonctionnentetmaîtriserlelangageSQLferontdevousunhommeouunefemmeenvogue.Voscollèguesviendrontvousvoirdès lorsqu’ilsouellesaurontbesoind’informationsessentielles.Voschefsvoussolliciterontpourdesconseils.Lesplusjeunesvousdemanderontdesautographes.Maisplus que tout, vous pourrez comprendre comment fonctionne votreentreprise(ouvotreassociation)danssesmoindresdétails.
IDébuterenSQL
DANSCETTEPARTIE:
Lesfondementsdesbasesdedonnéesrelationnelles.
LesconceptsdebasedeSQL.
Lesoutilsessentielsdesbasesdedonnées.
S
Chapitre1Lesbasesdedonnéesrelationnelles
DANSCECHAPITRE:
» Organiserl’information.
» Définirlanotiondebasesdedonnées.
» Définircequ’estunSGBD.
» Comparerdifférentsmodèlesdebasesdedonnées.
» Définirleconceptdebasededonnéesrelationnelle.
» Traiterdesproblèmesdeconceptiond’unebasededonnées.
QL (Structured Query Language, ou langage structuré de requêtes – prononcez esse-q-elle et non squale) est un langage standardspécifiquement conçu pour permettre aux gens de créer des bases de
données,d’yajouterdenouvellesdonnées,d’assurerlamaintenancedecesdonnées et d’en récupérer des portions précises. Développé dans lesannées 1970 par IBM, SQL a évolué au fil des ans jusqu’à devenir unstandard industriel. En tant que tel, il est maintenu par l’organisationinternationaledesstandards(ISO).
Ilexisteplusieurstypesdebasesdedonnéesdontchacuncorrespondàunconceptdemodélisationparticulier.
SQLaétéinitialementdéveloppépourtravaillersurdesdonnéescontenuesdansdesbasesbâtiesselonlemodèlerelationnel.Récemment,lestandardSQL a évolué pour incorporer des éléments dumodèle objet, produisantainsi des structures hybrides appelées bases de données objet-relationnel(ou relationnel-objet, selon les auteurs). Dans ce chapitre, je traite dustockage de données, je consacre une section à expliquer comment le
modèle relationnel se distingue des autresmodèles les plus connus, et jeprésente les fonctionnalités les plus importantes des bases de donnéesrelationnelles.
AvantdeparlerdeSQL,jevoudraispréciserunpoint:jedoisexpliquerceque j’entends par base de données.La signification de ce terme a évoluéaveclesordinateursetlamanièredontlesgensenregistrentetmaintiennentl’information.
ConserverlatracedeschosesAujourd’huilesgensutilisentlesordinateurspouraccomplirdestâchesquinécessitaient autrefois d’autres outils. Les ordinateurs ont remplacé lesmachinesàécrirepourrédigeretmodifierdesdocuments.Ilsontsurpasséles calculateurs électromécaniques dans le calcul mathématique. Ils ontaussi remplacé des millions de feuilles de papier et de fichiers dans lestockaged’informationssensibles.Lesordinateurstravaillentmieuxetplusrapidement que tous ces vieux outils.Cependant, tout cela a un coût. Lesutilisateursn’ontplusunaccèsphysiquedirectàleursdonnées.
Quandlesordinateurstombentenpanne(c’estrare,maiscelapeutarriver),ilestclassiquedelesremettreenquestionensedemandants’ilsaméliorentréellementquelquechose.C’estqu’autrefoisquandundossier«crashait»par terre, il suffisait de ramasser les papiers et de les ranger dans ledossier. Et hormis les tremblements de terre et autres désastres majeurs,riennesemblaitvraimentpouvoirfaire«tomberenpanne»unearmoireàdossiers. De même, on n’a jamais vu une armoire envoyer un messaged’erreur.Maisquandundisquedur«plante»,c’estuneautrehistoire.Vousnepouvezpas«ramasser»lesbitset lesoctets.Despannesmécaniques,électriquesoudesdéfaillanceshumainesfontparfoisdisparaîtredemanièredéfinitivedesdonnées.
Ilconvientdoncdeprendrequelquesmesurespourvousprotégercontrelaperteaccidentellededonnées.Voiciquatrecritèresauxquelsdoitrépondrelesystèmedestockagedel’informationquevouschoisirez:
» Ildoitêtrerapideetfaciledestockerdesdonnées,car
vousleferezsouvent.
» Lesupportdestockagedoitêtrefiable.Vousnevoulezpas
vousapercevoirunbeaumatinquevosdonnéesont
disparucommeparmagie.
» Ildoitêtresimpleetrapidederécupérerdesdonnées,
quellequesoitlaquantitéd’informationsdontvous
disposez.
» Vousdevezpouvoirrapidementetfacilementrécupérer
l’informationquevousrecherchezparmidestonnesde
données.
Les bases de données dignes de ce nom satisfont ces critères. Et si voussouhaitez stocker plus d’une dizaine de données, vous désirerezprobablementenutiliserune.
Qu’est-cequ’unebasededonnées?Letermebasededonnéesesttombédanslelangagecommunetaperdusonsensinitial.Pourcertainespersonnes,unebasededonnéesestunensembled’objets hétéroclites (agenda, liste de courses, parchemins magiques…).D’autrespersonnesluiaccordentunesignificationplusprécise.
Dans ce livre, je définirai une base de données comme un ensembled’enregistrementsintégrés,capabledefournirunedescriptiondelui-même.Et tout cela implique évidemment le passage par une technologieinformatiqueassociéeàcertainslangages(SQLenétantl’exemplequinousintéressedanscelivre).
Unenregistrementestlareprésentationd’unedonnéephysiqueoud’unobjetconceptuel. Imaginonsparexemplequevoussouhaitiezconserver la tracedes clients d’une entreprise. Vous assignez un enregistrement à chaqueclient.Chaqueenregistrementdisposedemultiplesattributstelsquelenom,l’adresse et le numéro de téléphone. Le nom, l’adresse et ainsi de suiteconstituentlesdonnées.
Une base de données est constituée de données et de métadonnées. Unemétadonnée est elle-mêmeune donnée qui décrit la structure des données«utiles»présentesdanslabase.Sivoussavezcommentvosdonnéessontarrangées, alors vous pouvez les retrouver. Puisque la base de donnéescontient une description de sa propre structure, on dit qu’elle estautodescriptive. La base de données est intégrée, car elle contient non
seulement des données, mais aussi la description des relations qui lesunissent.
La base de données conserve les métadonnées dans une zone nomméedictionnairedesdonnéesquidécrit les tables, lescolonnes, les index, lescontraintesettouteautrecaractéristiqueladéfinissant.
Commeunsystèmedefichierspleintexte(décritplusloindanscechapitre)ne dispose d’aucunemétadonnée, les applications conçues pour travailleravecdetelsfichiersdoiventcontenirdansleurprogrammedesinformationséquivalantauxmétadonnées.
Volumeetcomplexitéd’unebasededonnées
Il existe des bases de données de tout volume, d’un simple ensemble dequelques enregistrements au mammouth qui contient des millionsd’enregistrements.
» Unebasededonnéespersonnelleestconçuepourêtre
utiliséeparuneseulepersonnesurununiqueordinateur.
Unetellebaseadoptegénéralementunestructure
relativementsimpleetsonvolumeestlimité.
» Unebasededonnéesdépartementaleoudegroupede
travailestutiliséeparlesmembresd’undépartementou
d’ungroupedetravaild’uneorganisation.Cetypedebase
dedonnéesoccupegénéralementunvolumeplus
importantqu’unebasededonnéespersonnelleetest
nécessairementpluscomplexe,carildoitgérerlesaccès
simultanésdemultiplesutilisateursauxmêmesdonnées.
» Unebasededonnéesorganisationnellepeutêtre
énorme.Cetypedebaseestutilisépourstockerles
informationsd’importantesorganisationsouentreprises.
Qu’est-cequ’unsystèmedegestiondebasesdedonnées?
Bonnequestion.Unsystèmedegestiondebasesdedonnées(SGBD)estunensemble de programmes utilisés pour définir, administrer et traiter desbases de données et leurs applications associées. La base de données«administrée»est,paressence,unestructurequevouscréezpourcontenirdes données. Un SGBD est l’outil que vous utilisez pour créer cettestructureettraiterlesdonnéesquisetrouventdanslabasededonnées.
De nombreux SGBD sont disponibles sur le marché. Quelques-uns nefonctionnentquesurdesgrandssystèmes(oumainframes),desordinateursportables, des tablettes. Toutefois, la tendance de ces produits est defonctionner sur de multiples plates-formes ou sur des réseaux quicontiennent différentes classes de machines. Une tendance encore plusmarquée est de stocker les données dans des centres d’hébergement dedonnées(datacenters),voiredelesstockerdanslecloud,quipeutêtreuncloudpublicgéréparuneentreprisetellequ’Amazon,GoogleouMicrosoft,via Internet, ou un cloud privé géré par l’organisation qui stocke lesdonnéessursonintranet.
Denosjours,cloudestuntermeàlamodeutilisésansarrêtdanslescerclestechniques.Toutcommeceschosesblanchesdansleciel,sescontourssontindéfinisetilsembleflotterquelquepart.Enréalité,c’estunensemblederessources informatiques accessibles depuis un navigateur, sur Internet ousurunintranetprivé.Cequidistinguelesressourcesinformatiquesdansleclouddecellesd’undatacenterphysique,c’est le faitqueces ressourcessontaccessiblesviaunnavigateurplutôtqueviaunprogrammequiyaccèdedirectement.
UnSGBDquifonctionnesurdiversesplates-formes,aussibienpetitesquegrandes,estditpouvoirmonterencharge.
Quelle que soit la taille de l’ordinateur sur lequel fonctionne la base dedonnées, et que lamachine soit connectéeounon à un réseau, le flot desinformationsentrel’utilisateuretlabasededonnéesesttoujourslemême.La Figure 1.1 montre comment l’utilisateur communique avec la base dedonnées via le SGBD. Le SGBD masque physiquement les détails dustockagedesdonnées,desortequel’applicationn’aàsepréoccuperquede
lamanipulationdecelles-cietnondelamanièredontellessontextraitesoustockées.
FIGURE1.1Diagrammedeblocd’unsystèmed’informationàbasedeSGBD.
LAVALEURESTDANSLASTRUCTURE,PASDANSLESDONNÉES
Imaginonsuninstantquel’onréduiseunêtrehumainauxatomesqui
lecomposent(carbone,hydrogène,oxygène,nitrogène,plusquelques
autresdontlenomm’échappe).Queresterait-ildevous?Bienpeude
choses en vérité. Mais c’est une mauvaise manière de prendre le
problème.Lesgensnesontpassimplementcomposésdecollections
d’atomes isolés. Nos atomes se combinent pour former des
protéines, des enzymes, des hormones et bien d’autres substances
qui coûteraient des millions d’euros le sachet dans l’industrie
pharmaceutique.Lastructureprécisedecescombinaisonsd’atomes
est justementcequi leurdonneunesihautevaleur.Paranalogie, la
structure de nos bases est ce qui rend possible l’interprétation de
données n’ayant par elles-mêmes aucune signification précise. La
structureajouteàcesdonnéesinertesdusensetdelacohérence.Elle
permet d’en dégager des schémas, des trames, des tendances, et
ainsidesuite.Desdonnéesnonstructurées (à l’instard’atomesnon
combinés)n’ontquepeuoupasdevaleurdutout.
LesfichierspleintexteQuandils’agitdestockerdesdonnéesnonstructurées,lefichierpleintextepeut se révéler être une excellente solution. Un tel fichier contient uneséquenced’enregistrementsprésentéedansununiqueformatetriend’autre(les données, toutes les données,mais rien que les données). Puisque cefichier ne contient aucune information sur la structure de l’information(métadonnées),iloccupeunespaceminimum.
Supposons que vous désiriez stocker les noms et les adresses des clientsaméricains de votre entreprise dans un fichier plein texte. Vous pourriezadopterlastructuresuivante:
HaroldPercival26262S.HowardsMillRd
WestminsterCA92683
JerryAppel32323S.RiverLaneRd
SantaAnnaCA92705
AdrianHansen232GlenwoodCourt
AnaheimCA92640
JohnBaker2222LafayetteSt
GardenGroveCA92643
MichaelPens77730S.NewEraRd
IrvineCA92715
BobMichimoto25252S.KelmsleyDr
StantonCA92610
LindaSmith444S.E.SeventhSt
CostaMesaCA92635
RobertFunnell2424SheriCourt
AnaheimCA92640
BillCheckal9595CurryDr
StantonCA92610
JedStyle3535RandallSt
SantaAnnaCA92705
Commevouspouvezlevoir,lefichiernecontientquelesdonnées.Chaquechamp occupe un espace fixe (par exemple, le champ Nom
occupe15caractères)etaucunestructurenesépareunchampd’unautre.Lapersonnequiacréécettebasededonnéesadécidédelapositionetdelalongueurdeschamps.Toutprogrammequivoudraitutilisercefichierdevra«connaître»lamanièredontleschampssontorganisés,puisquelefichiernecontientaucuneinformationàcesujet.
Dufaitdeleursimplicité,lesfichierspleintextepeuventoffrirunegranderapidité de traitement. Par contre, toute la complexité de la gestion esttransféréeauxprogrammesqui lesgèrent.Lesapplicationsdoivent savoirexactement où et comment les données sont enregistrées dans le fichier.C’estpourquoil’utilisationd’unfichierpleintexten’estintéressantequesurde petits systèmes. Dès que l’on dépasse une certaine échelle, ilsdeviennentunfreinaudéveloppement.
Une véritable base de données, si elle contient effectivement un certainnombre d’informations qui ne sont pas directement utiles, présentel’avantage de pouvoir être exploitée sur de nombreuses plates-formesmatérielleset systèmesd’exploitation. Il estaussiplus simpled’écrireunprogrammequimanipuleunebasededonnéesqu’unfichierpleintexte,carle programme n’a pas à connaître à l’avance l’organisation des donnéesqu’iltraite.
Deplus, la logiqued’accèsauxdonnéesetdeleurmanipulationn’apasàêtreintégréedansleprogramme,carellesetrouvedéjàdansleSGBD.Parconséquent, il n’est pas nécessaire de reprogrammer cette portion duprogrammequandils’agitdeportercedernierd’uneplate-formematérielleàuneautre.Etc’est làoù les fichiersplein texteatteignent trèsvite leurslimites.
LesmodèlesdebasededonnéesDans les années1950, les premières bases dedonnées étaient structuréesselonunmodèlehiérarchique.Ellesposaientdesproblèmesderedondancede données, et la rigidité de leur structure compliquait leurmodification.Bientôt, elles furent suivies par des bases de données qui collaient aumodèle réseau, pour tenter d’éliminer les inconvénients principaux dumodèle hiérarchique. Les bases de données en réseau minimisent laredondance,maisauprixd’unecomplexitéstructurelleaccrue.
Quelquesannéesplustard,leDR.E.F.Coddd’IBM«inventa»lemodèlerelationnel,quiminimisaitlaredondancetoutenpermettantdecomprendre
facilementlastructure.LelangageSQLaétéconçupourtravaillersurdesbasesdedonnéesrelationnelles.L’apparitiondetellesbasespermitdefairepasser les bases de données hiérarchiques et réseau aux oubliettes del’histoire.
Un nouveau phénomène est l’émergence de bases de données désignéescomme NoSQL, qui n’ont pas la structure des bases de donnéesrelationnelles et qui n’utilisent pas le langage SQL. Je ne traite pas desbasesdedonnéesNoSQLdanscelivre.
LemodèlerelationnelLe Dr E.F. Codd d’IBM « inventa » le modèle relationnel de base dedonnées en 1970, mais ce modèle ne commença à être utilisé dans desproduitsqu’unedizained’annéesplustard.Ironiedel’histoire,cenefutpasàIBMquerevintlaprimeurdedélivrerlepremierdecesproduits.L’actede naissance fut signé par une toute jeune société qui nomma son bébéOracle.
Lesbasesdedonnéesrelationnellesontremplacélesanciensschémas,carlemodèlerelationnelprésenteuncertainnombred’avantagessurceuxquil’ontprécédé.Leplusimportantdecesavantagesestsansdouteque,dansunebasededonnéesrelationnelle,vouspouvezchangerlastructuredecettebase sans pour autant avoir à modifier les applications basées sur lesanciennes structures. Supposons par exemple que vous ajoutiez une ouplusieursnouvellescolonnesàunetabledebasededonnées.Vousn’aurezpas besoin de changer les applications précédemment écrites pour traitercettetable,àmoinsquevousn’ayezmodifiéuneouplusieursdescolonnesmanipuléesparlesditesapplications.
Bienentendu,sivoussupprimezunecolonneréférencéeparuneapplicationexistante,cettedernièrerisquedeneplusfonctionnercorrectement.Etc’estvraiquelquesoitlemodèledebasededonnéesquevousutilisez.Iln’yapas de meilleure manière pour « planter » une application de base dedonnéesquedeluidemanderderécupéreruneinformationquin’existeplus.
Lescomposantsd’unebasededonnéesrelationnelle
Lesbasesdedonnéesrelationnelles tirent leur flexibilitédufaitque leursdonnées résident dans des tables largement indépendantes les unes desautres.Vous pouvez ajouter, supprimer oumodifier des données dans unetablesansmodifiercellesquisetrouventdanslesautrestables,dumomentque la structure affectée n’est pas un parent d’autres tables (les relationsparent-enfantentrelestablessontexpliquéesdansleChapitre5).Danscettesection,jevaisvousmontrerenquoiconsistentcestablesetcommentellessont liées aux autres éléments qui composent une base de donnéesrelationnelle.
Devinequivientdînercesoir?Nombreusessontlesrelationsquej’inviteàmatabledurantlesvacances.Lesbasesdedonnéesontaussidesrelations,maischacunedeleurrelationdisposedesapropretable.Unebasededonnéesrelationnelleestconstituéed’uneoudeplusieursrelations.
Unerelationestuntableauàdeuxdimensions,doncformédelignesetdecolonnes.Chaquecelluledutableaucontientuneetuneseulevaleur,etdeuxlignesnepeuventpasêtreidentiques.
Les tableaux à deux dimensions sont ceux que vous utilisez dans destableursde typeMicrosoftExcelouOpenOffice.orgCalc.Les statistiquesd’un joueurdebase-ballque l’on retrouveaudosdecartesdecollectionsont un autre exemple de tels tableaux. On trouve sur ces cartes descolonnespour l’année, l’équipe, lesparties, lesdifférents typesdepointsmarqués. Une rangée traite d’une année durant laquelle le joueur auraparticipéauxévénementssportifsmajeurs.Vouspouvezstockercesdonnéesdansunerelation(une table)quiadopterait lamêmestructuredebase.LaFigure 1.2 représente une table d’une base de données relationnelle quicontient les statistiquesd’uncertain joueur.Dans lapratique, cegenredetableproposeraitdesstatistiquesrelativesàtouslesjoueursd’uneéquipe.
FIGURE1.2Unetablecontenantlesstatistiquesd’unjoueurdebase-ball.
Lescolonnesd’untableausontconsistantes,c’est-à-direqu’unecolonneala même signification dans chaque ligne. Si une colonne contient le nomd’un joueur dans une ligne, elle devra contenir le nom d’un joueur danstoutesleslignes.L’ordredanslequelleslignesetlescolonnesapparaissentdansletableaun’aaucunesignification.LeSGBDtraitelatabledelamêmemanière,quelquesoit l’ordredesescolonnes.Ilenvademêmepourleslignes.
Chaquecolonnedelatabled’unebasededonnéesreprésenteunattributdelatable.Lasignificationd’unecolonneestlamêmepourtoutesleslignesdelatable.Parexemple,unetablepeutcontenirlesnoms,adressesetnumérosdetéléphonedetouslesclientsd’uneorganisation.Chaquelignedelatable(aussinomméeenregistrementoutuple)contientlesinformationsrelativesà un seul client. Chaque colonne représente un unique attribut, tel que lenuméro du client, le nom du client, la rue du client, la ville du client, lecode postal du client ou encore son numéro de téléphone. LaFigure 1.3 montre quelques-unes des lignes et des colonnes d’une telletable.
FIGURE1.3Chaquelignedelabasededonnéescontientunenregistrement;chaque
colonnedelabasededonnéescontientununiqueattribut.
Danscemodèledebasededonnées,lesrelationscorrespondentauxtablesfigurantdans toutebasededonnées fondée sur cemodèle.Répétez-ledixfoisrapidementpourvousensouvenir.
Profitezdelavue
Il vous est probablement déjà arrivé de vous arrêter sur la route pourcontemplerlavue.Lesbasesdedonnéesontaussidesvues,mêmesiellesne sont pas aussi pittoresques. Les vues des bases de données tirent leurbeautédufaitqu’ellessontextrêmementutilesquandvoustravaillezsurvosdonnées.
Lestablespeuventcontenirdenombreusescolonnesetlignes.Ilarrivequetouteslesdonnéesvousintéressent,et ilarriveaussiquecenesoitpaslecas. Seules quelques colonnes de la table retiennent votre attention ouseulesquelqueslignesrépondentàvosconditions.Certainescolonnesd’unetableetcertainescolonnesd’uneautre tablepeuventvous intéresser.Pouréliminer les données dont vous n’avez pas besoin dans l’instant, vouspouvezcréerunevue.Unevueestunsous-ensembled’unebasededonnéesqu’une application est capable de traiter. Elle peut contenir des partiesd’uneoudeplusieurstables.
Les vues sont parfois appelées tables virtuelles. Du point de vue del’applicationoudel’utilisateur, lesvuessecomportentcommedestables.Pourautant,ellesn’ontpasd’existencephysique.Lesvuesvouspermettentdejeterunœilsurvosdonnées,maisellesnefontpaspartiedesdonnéesenelles-mêmes.
Imaginons par exemple que vous travailliez sur une base de données quicontientune tableCLIENTSetune tableFACTURES.La tableCLIENTSpossèdelescolonnesCLIENT_ID,NOM,PRENOM,RUE,VILLE,ETAT,CODE_POSTAL et TELEPHONE. La table FACTURES contient lescolonnes NUMERO_FACTURE, CLIENT_ID, DATE, TOTAL_VENTE,TOTAL_REMISetMETHODE_PAIEMENT.
Unresponsabledesventesdupaysveutvoiràl’écranleprénom,lenometlenumérode téléphonedesclients.Vouspouvezcréeràpartirde la tableCLIENTSunevuequicontienneseulementcestroiscolonnesetpermetteauresponsable de n’afficher que les informations dont il a besoin, sanss’encombrer avec le contenudes autres colonnes.LaFigure1.4montre àquoiressembleraitcettevue.
Unresponsableencharged’undépartementoud’unétatpourraitvouloirnevisualiserquelesnomsetlesnumérosdetéléphonedesclientsdontlecodepostalestcomprisentre90000et93999(CaliforniecentraleetCaliforniedu Sud). Une vue qui appliquerait une restriction sur les lignes et lescolonnes voulues pourrait effectuer ce travail. La Figure 1.5montre d’oùcettevuetireraitsesdonnées.
FIGURE1.4LavueduRESPONSABLEDESVENTESdérivedelatableCLIENTS.
FIGURE1.5LavueduRESPONSABLEDUDEPARTEMENTnecontientquequelques-
unesdeslignesdelatableCLIENTS.
LeresponsabledesventesencourspeutvouloirvisualiserlesdonnéesNOMet PRENOM de la table CLIENTS ainsi que les données DATE,
TOTAL_VENTE,TOTAL_REMISetMETHODE_PAIEMENTde la tableFACTURES,quandTOTAL_REMISvautmoinsqueTOTAL_VENTE,cequiseralecassileclientn’apasencoreentièrementréglésafacture.Ilfautdoncélaborerunevuequicontiennedesdonnéesextraitesdesdeuxtables.LaFigure1.6montre le flux de données entre la vue du responsable desventesencoursetlestablesCLIENTSetFACTURE.
FIGURE1.6LavueEN_COURStiresesdonnéesdedeuxtables.
Lesvuessonttrèsutilescarellesvouspermettentd’extraireetdeformaterdesdonnéesd’unebasededonnéessansaltérerphysiquementlesdonnéesstockées.Ellesprotègentaussilesdonnéesquevousnevoulezpasafficher,car elles ne les contiennent pas. Le Chapitre 6 explique dans le détailcommentcréerunevueenSQL.
Schémas,domainesetcontraintesUne base de données n’est pas seulement un ensemble de tables. Denombreuses structures supplémentaires, sur différents niveaux, permettentde maintenir l’intégrité des données. Le schéma de la base de donnéesdétaillel’organisationgénéraledestables.Ledomained’unecolonned’unetablevousindiquequellesvaleursvouspouvezstockerdanscettecolonne.Vouspouvezappliquerdescontraintesàune tabled’unebasededonnées
pour empêcher que quelqu’un (dont vous-même) n’enregistre des donnéesnonvalidesdanslatable.
SchémasL’intégralité de la structure d’une base de données est stockée dans sonschémaouvueconceptuelle.Cettestructureestquelquefoisaussiappeléevuelogiquecomplètedelabasededonnées.Leschémaestunemétadonnéeet, en tant que telle, une partie intégrante de la base de données. Lamétadonnée,quidécritlastructuredelabasededonnées,eststockéedansdes tables qui ressemblent en tout point aux tables qui contiennent desdonnéesclassiques.Unemétadonnéen’estriendeplusqu’unedonnée.C’estlabeautédelachose.
DomainesUn attribut d’une relation (autrement dit une colonne d’une table) peutn’accepter qu’un nombre fini de valeurs. L’ensemble de ces valeursautoriséesconstitueledomainedel’attribut.
SupposonsquevoussoyezunvendeurdevoituresetquevousdeviezgérerlenouveaumodèleCurarriGT4000coupésport.Vousconservez la tracedes voitures que vous avez en stock dans une table que vous nommezINVENTAIRE.Vousnommezl’unedescolonnesdecette tableCOULEUR,carellecontientlacouleurextérieuredechaquevoiture.LaGT4000existeenquatrecoloris:gris,noir,blancetrouge.Cesquatrecouleursconstituentledomainedel’attributCOULEUR.
ContraintesUne contrainte est un élément important (quoique trop souvent négligé)d’une base de données. C’est une règle qui précise les valeurs que peutprendreunattributd’unetable.
Enappliquantdescontraintesàunecolonne,vouspouvezempêcherlesgensdesaisirdesdonnéesnonvalidesdanscettecolonne.Bienentendu,chacunedes valeurs appartenant au domaine de la colonne doit satisfaire lescontraintesquipèsentsurcettedernière.Commeje l’aimentionnédanslasection précédente, le domaine d’une colonne est l’ensemble des valeursquecettecolonnepeutcontenir.Unecontrainteestunerestrictionsurceque
la colonne a le droit de contenir. Les caractéristiques d’une colonne detable,plus les contraintesqui s’appliquent à cette colonne,déterminent ledomaine de la colonne. En appliquant des contraintes, vous pouvezempêcher la saisie d’une donnée qui n’appartient pas au domaine de lacolonne.
Dansl’exempleduvendeurdevoitures,vouspouvezcontraindrelabasededonnées à n’accepter que les quatre couleurs dumodèle dans la colonneCOULEUR. Si l’opérateur de saisie tente de rentrer une autre teinte, parexemplevert,lesystèmerefuseralasaisie.
Vousvousdemandezdéjàcequivasepassersi leconstructeurdécidedesortir une série limitée de la Curarri GT 4000 coupé sport verte ! Laréponse est simple (roulez tambours) : il va falloir que les développeurschargésdelamaintenancedelabasededonnéesmodifientledomainedelacolonne COULEUR pour s’adapter au nouveau modèle. Ce genre desituation se produit tout le temps, impliquant donc des adaptations de lastructurede labasededonnées.Seules lespersonnesquisaventcommentprocéder (et vous en faites partie) seront capables d’éviter un désastrecommercial.
LemodèleobjetopposéaumodèlerelationnelLemodèle relationnel s’est révélé extraordinairement utile dans un grandnombre d’applications. Cependant, il n’est pas exempt de défauts. Cesproblèmes sont devenus plus évidents avec l’avènement des langages deprogrammationorientésobjettelsqueleC++,JavaetC#.Detelslangagessont capables de s’attaquer à des questions bien plus complexes que leslangages traditionnels, en particulier parce qu’ils implémentent desconcepts tels que l’extensibilité des types de données, l’encapsulation,l’héritage, le lien dynamique aux méthodes, les objets complexes etcompositesetl’identitédesobjets.
Je ne vais pas expliquer dans ce livre à quoi correspondent toutes cesnotions (même si nous ferons référence à certaines d’entre ellesultérieurement). Il faut simplement comprendre que lemodèle relationnelclassiquen’estpascompatibleavecunbonnombredecesfonctionnalités.Ilenrésultequedessystèmesdegestiondebasesdedonnéesbaséssurle
modèle objet ont été développés et sont aujourd’hui commercialisés.Cependant,leurpartdemarchéestencorelimitéeàcejour.
Score final : bases de données relationnelles : 1 ; bases de donnéesorientéesobjet:0.
Lemodèleobjet-relationnelLesconcepteursdebasesdedonnéessontconstammentenquêtedumeilleurmondepossible.Ilssongent:«Neserait-ilpasfabuleuxsinouspouvionsdisposer de tous les avantages que procurent les systèmes de gestion debasesdedonnéesorientésobjettoutenrestantcompatiblesaveclesystèmerelationnelquenousconnaissonsetapprécionstous?»Cetypederéflexionamenéaumodèleobjet-relationnel.LesSGBDobjet-relationnelétendentlemodèle relationnel en y intégrant la gestion de la modélisation orientéeobjetdesdonnées.Desfonctionnalitésorientéesobjetontété rajoutéesaustandard international SQL pour permettre aux vendeurs de SGBDrelationnelsde transformer leursproduitsenSGBDorientésobjet, toutenrestantcompatiblesaveclestandard.SilestandardSQL-92netraitequedumodèle purement relationnel, le standard SQL-1999 (également appeléSQL3) décrit un modèle de bases de données objet-relationnel.SQL:2003 inclut encore plus de fonctionnalités orientées objet, et lesversions suivantes du standard SQL ont poussé encore plus loin dans cesens.
JeprésentedanscelivrelestandardinternationalSQLISO/IEC.C’est-à-dire,etpour l’essentiel,unmodèledebasesdedonnéesrelationnelles.Jedécris aussi les extensions orientées objet qui ont été rajoutées dansSQL:1999 ainsi que celles introduites dans les versions suivantes. Lesfonctionnalités orientées objet du nouveau standard permettent auxdéveloppeurs d’utiliser des bases de données SQL pour résoudre desproblèmes tropcomplexes à résoudrepour les anciensconceptspurementrelationnels. Les vendeurs de SGBD incorporent les fonctionnalitésorientéesobjetdustandardISOdansleursproduits.Quelques-unesdecesfonctionnalités existent depuis des années, mais d’autres restent encore àinclure.
Considérationssurlaconceptiondebasesdedonnées
Une base de données est la représentation d’une structure physique ouconceptuelle telle qu’une organisation, une usine de voitures ou lesstatistiquesdesperformancesde tous lesclubsdebase-ball.Laprécisionde la représentation dépend du niveau de détail apporté lors de laconception.Lasommed’effortsquevousinvestissezdanslaconceptiondevotre base de données devrait dépendre du type d’information que vouscomptezystocker.Tropdedétailsrimeaveceffortsinutiles,tempsperduetgaspillage d’espace sur le disque. Pas assez de détails peut rendre votrebasededonnéesinutilisable.
Etudiezleniveaudedétaildontvousavezbesoinsurl’instantetceluidontvousaurezbesoindanslefutur.C’estàl’avenirquevousdevezpenserlorsdevotre conception.Mais ne soyezpas surpris si vousdevezprocéder àquelquesajustementspoursatisfaireauxcontraintesdumonderéeletàleursévolutions.
Les systèmes de gestion de bases de données actuels, dotés d’interfacesgraphiquesattrayantesetd’outilsdeconceptionintuitifs,peuvententretenirchez le concepteur un faux sentiment de sécurité.Ces systèmes laissent àpenser que la conception d’une base de données s’apparente beaucoup àcelled’unefeuilledecalculdansuntableur.Malheureusement,cen’estpasle cas. La conception d’une base de données est une tâche complexe. Sivous vous y prenez mal, vous produirez une base de données qui nerésistera pas au temps.Bien souvent, le problème n’apparaît que lorsquevousavezdépensébeaucoupd’énergieàsaisirlesdonnées.Etquandvousréalisez enfin que ce problème existe, il a généralement pris une telleampleurque la seule solutionestde reprendreà zéro la conceptionde labasededonnéeset la saisiedecesdernières.Leboncôtédeschosesestque cela vous sert de leçon en vous poussant à construire une secondeversiondebienmeilleurequalitéquelapremière
S
Chapitre2LesbasesdeSQL
DANSCECHAPITRE:
» ComprendreSQL.
» SedéfairedequelquesidéespréconçuessurSQL.
» JeterunœilsurlesdifférentsstandardsSQL.
» SefamiliariseraveclescommandescommunesdeSQLetlesmotsréservés.
» Représenterdesnombres,descaractères,desdates,desheuresetd’autrestypesdedonnées.
» Etudierlesvaleursnullesetlescontraintes.
» MettreSQLenmarchesurunsystèmeclient/serveur.
» SQLenréseau.
QL est un langage souple que vous pouvez utiliser de différentesmanières.C’estl’outilleplusemployépourcommuniqueravecunebasededonnéesrelationnelle.Danscechapitre,j’expliqueraicequ’estSQL
et ce qu’il n’est pas, en le distinguant plus particulièrement des autreslangages.Puis,jedécrirailescommandesetlestypesdedonnéesqueSQLsupporte dans sa version standard avant de dévoiler quelques conceptsclés:lesvaleursnullesetlescontraintes.Enfin,jeprésenterairapidementla place queSQLoccupe dans un environnement client/serveur, ainsi quesurInternetetsurdesintranets.
CequeSQLn’estpasLapremièrechosequ’ilfautcomprendrequandonparledeSQLestquecen’est pas un langage procédural comme le Basic, le C, le C++, le C# etJava.Pourrésoudreunproblèmeàl’aided’undeceslangagesprocéduraux,
vousécrivezuneprocédurequieffectueuneopérationspécifique,puisuneautre,etcejusqu’àcequelatâchesoitaccomplie.Laprocédurepeutêtreuneséquencelinéaireoubouclersurelle-même,maisdanslesdeuxcasleprogrammeurspécifiel’ordred’exécution.
SQLestnonprocédural. Pour résoudre un problème avec SQL, vous luiindiquezsimplementcequevousvoulez(àl’égald’Aladinetdesalampemagique) au lieu d’indiquer au système comment récupérer ce que vousvoulez.Le systèmedegestiondebasesdedonnées (SGBD)décidede lameilleuremanièred’exaucervotresouhait.
JeviensdevousdirequeSQLn’estpasunlangageprocédural.C’estdansl’ensemblevrai.Cependant,desmillionsdeprogrammeurssonthabituésàrésoudredesproblèmesd’unemanièreprocédurale.C’estpourquoiilyaeuces dernières années une pression considérable pour que de tellesfonctionnalitéssoientajoutéesàSQL.C’estpourquoicelangagecomprendaujourd’hui des instructions qui se rattachent à la programmationprocédurale tellesque lesblocsBEGIN, l’instructionIF, les fonctions etlesprocédures.Toutcelaaétéajoutédemanièreàpouvoirstockersur leserveurdesprogrammesutilisablespardemultiplesutilisateurs.
Pour illustrer ce que je veux dire par « indiquer au système ce que vousvoulez»,supposezquevousdisposiezd’unetableEMPLOYESetquevoussouhaitiez y récupérer les lignes correspondant à toutes les personnes« senior ». Selon vous, un senior se définit comme quelqu’un dont l’âgedépasse 40 ans ou qui gagne plus de 60 000 € par an. Vous pouvezrécupérer les informations que vous recherchez en utilisant la requêtesuivante:
SELECT*FROMEMPLOYESWHEREAGE>40OR
SALAIRE>600000;
Cette requête retourne toutes les lignes de la table EMPLOYES danslesquellesoubienlavaleurdelacolonneAGEestsupérieureà40oubienlavaleurdelacolonneSALAIREestsupérieureà60000(oubienlesdeuxà la fois). En SQL, vous n’avez pas besoin de préciser commentl’informationdoitêtrerécupérée.Lemoteurdelabasededonnéesexaminelabaseetdécideparlui-mêmedelamanièrederépondreàvotrerequête.Vousn’avezbesoinquedespécifierquellesdonnéesvousrecherchez.
Unerequêteestunequestionquevousposezà labasededonnées.Siunedonnéecontenuedanslabaserépondauxconditionsquevousformulezdans
votrerequête,SQLvousrenverracettedonnée.
Les implémentations actuelles de SQL ne comportent pas la plupart desconstructionsdebaseprésentesdanslesautreslangagesdeprogrammation.Lesapplicationsdumonde réelutilisentgénéralement aumoinsquelques-unesdecesconstructions,c’estpourquoiSQLestqualifiédesous-langagede données. Même avec les extensions ajoutées en 1999, 2003,2005 et 2008, vous devrez utiliser SQL en combinaison avec un langageprocédural,telqueleC++,pourproduiredesapplicationscomplètes.
Vous pouvez extraire de l’information à partir d’une base de données dedeuxmanières:
» Enformulantunerequêteadhocdepuislaconsolede
l’ordinateurentapantlesinstructionsSQLpuisen
lisantlerésultatàl’écran.Laconsoleestleterme
traditionnellementutilisépourdésignerlematérielquijoue
lerôledeclavieretd’écransurlessystèmesPC.Vous
pouvezformulerainsivosrequêtessivoussouhaitez
obtenirrapidementuneréponseàunequestionspécifique.
Vousn’avezjamaiseubesoind’unecertaineinformationet
vousn’enaureztrèsvraisemblablementplusjamaisbesoin.
Maiscejour-ci,àcetteheure-ci,c’estexactementcequ’il
vousfaut.TapezlarequêteSQLappropriéesurvotre
clavier,etlaréponsevas’affichersurl’écranenmoinsde
tempsqu’iln’enfautpourledire.
» Enexécutantunprogrammequirécupère
l’informationdanslabasededonnéesetproduitun
rapportsoitàl’écran,soitsuruneimprimante.Ajouter
unerequêtedirectementdansvotreprogrammeestla
meilleuresolutionsicetterequêteestcomplexeetsivous
comptezl’utiliserplusieursfois.Vousn’avezainsiàla
formulerqu’unefois,puisàyfaireappelaussisouventque
vouslevoulez.LeChapitre16vousexpliquecomment
incorporerducodeSQLdansdesprogrammesécritsdans
unautrelangage.
Un(tout)petitpeud’histoireSQLestnédansleslaboratoiresderecherched’IBM,toutcommelathéoriedesbasesdedonnéesrelationnelles.Audébutdesannées1970,alorsqueles chercheurs d’IBM travaillaient sur ce qui allait devenir les SGBDrelationnels (ou SGBDR), ils créèrent un sous-langage de données pourtravaillersurcessystèmes.IlsnommèrentlapremièreversiondecelangageSEQUEL (Structure English QUEry Language ou Langage de requêtesstructuré).Cependant,quandvintlemomentdedistribuercelangagesouslaformed’unproduit,ilsvoulurents’assurerquelesgenscomprendraientenquoi leur produit était différent de toutes les précédentes versions deSGBD.C’estpourquoiilsdécidèrentdedonneraunouveauproduitunnomquisoitdifférentdeSEQUEL,maisquisoitassimilableàunproduitdelamêmefamille.IlslenommèrentdoncSQL.
LasyntaxedeSQLestuneformed’anglaisstructuré,etc’estdelàqu’iltientson nom. Toutefois, SQL n’est pas un langage structuré au sens où lesinformaticiens l’entendent.C’estpourquoi,endépitdecequiest répandu,SQL n’est pas l’acronyme de « langage de requête structuré ». C’estsimplementuneséquencedetrois lettressanssignification,commelenomdulangageCquinesignifierien.
Les travaux d’IBM sur les bases de données relationnelles et sur SQLdevinrenttrèspopulairesdansl’industrieavantmêmequ’IBMn’introduiseson SGBD SQL/DS en 1981. À cette époque, Relational Software Inc.(aujourd’huiOracleCorporation)avaitdéjàdistribué sonpremierSGBD.Àpeinenés,cesproduits imposèrent immédiatementunstandardpourunenouvelle classe de systèmes de gestion de bases de données. Ilsincorporaient SQL, qui devint de facto le standard des sous-langages dedonnées. Les éditeurs d’autres systèmes de gestion de bases de donnéesproduisirent leurs propres versions de SQL. Ces versions comportaienttouteslesfonctionnalitésdesproduitsd’IBMenyrajoutantdesextensionspourtirerlemeilleurpartiduSGBDsous-jacent.Puisquetousleséditeursutilisaient une forme particulière de SQL, la compatibilité entre lesdifférentsSGBDdumarchéétaitévidemmentfaible.
UneimplémentationestunSGBDRparticulierquifonctionnesuruneplate-formematériellespécifique.
Rapidement, un mouvement se créa pour réaliser un standarduniversellementreconnudeSQLauqueltousleséditeurspourraientadhérer.En1986,l’ANSIpubliaunstandardformelnomméSQL-86.L’ANSImitàjour sonstandarden1989 (SQL-89)puisen1992 (SQL-92).Chaque foisque les éditeurs de SGBDR sortaient de nouvelles versions de leursproduits, ils tentaient de coller toujours plus à ces spécifications. C’estpourquoi,finalement,SQLestdevenuunlangagevéritablementstandardetportable.
La dernière version complète du standard SQL est SQL:2011(ISO/IEC9075X:2011).Danscelivre,jetraitedeSQLcommelestandardSQL:2011ledécrit.TouteimplémentationspécifiquedeSQLs’écartebienentenduplusoumoinsdecestandard.Maisleséditeursdelogicielstententde supporter un sous-ensemble essentiel et cohérent du langage SQLstandard.LaversioncomplètedustandardISO/IECestproposéeàlaventesur http://webstore.ansi.org, mais vous ne souhaiterez sansdoutepasl’acquériràmoinsquevousn’entrepreniezdecréervotrepropresystèmedegestiondebasesdedonnéesfondésurlestandard.Lestandardesthautement technique,c’est-à-direvirtuellement incompréhensiblepourquin’apasétudiéleslangagesinformatiques.
LescommandesSQLLe langage SQL comporte un nombre limité de commandes qui sontspécifiquement liéesà lamanipulationdesdonnées.Quelques-unesdecescommandes sontdes fonctionsdedéfinitiondedonnées,d’autres sontdesfonctionsdemanipulationdedonnées,etd’autresencoredes fonctionsdecontrôle de données. Je traite des commandes de définition et demanipulationdedonnéesdans lesChapitres 4 à 13 et des commandes decontrôlededonnéesdanslesChapitres14et15.
Pour se conformer au standard SQL:2011, une implémentation doitcomporter toutes les fonctionnalités de base. Elle peut aussi inclurecertainesdes extensions à cenoyaudur (comme ledécrit la spécificationSQL:2011).LeTableau2.1 liste lescommandesdebasedeSQL:2011.Sivous êtes de ces programmeurs qui aiment essayer de nouvellesfonctionnalités,rejoignezl’équipe!
TABLEAU2.1LescommandesdeSQL:2011.
ADD DEALLOCATEPREPARE FREELOCATOR
ALLOCATECURSOR DECLARE GETDESCRIPTOR
ALLOCATE
DESCRIPTOR
DECLARELOCAL
TEMPORARYTABLE
GETDIAGNOSTICS
ALTERDOMAIN DELETE GRANTPRIVILEGE
ALTERROUTINE DESCRIBEINPUT GRANTROLE
ALTERSEQUENCE
GENERATOR
DESCRIBEOUTPUT HOLDLOCATOR
ALTERTABLE DISCONNECT INSERT
ALTERTRANSFORM DROP MERGE
ALTERTYPE DROPASSERTION OPEN
CALL DROPATTRIBUTE PREPARE
CLOSE DROPCAST RELEASESAVEPOINT
COMMIT DROPCHARACTERSET RETURN
CONNECT DROPCOLLATION REVOKE
CREATE DROPCOLUMN ROLLBACK
CREATE
ASSERTION
DROPCONSTRAINT SAVEPOINT
CREATECAST DROPDEFAULT SELECT
CREATE
CHARACTERSET
DROPDOMAIN SETCATALOG
CREATE
COLLATION
DROPMETHOD SETCONNECTION
CREATEDOMAIN DROPORDERING SETCONSTRAINTS
CREATEFUNCTION DROPROLE SETDESCRIPTOR
CREATEMETHOD DROPROUTINE SETNAMES
CREATEORDERING DROPSCHEMA SETPATH
CREATE
PROCEDURE
DROPSCOPE SETROLE
CREATEROLE DROPSEQUENCE SETSCHEMA
CREATESCHEMA DROPTABLE SETSESSION
AUTHORIZATION
CREATESEQUENCE DROPTRANSFORM SETSESSION
CHARACTERISTICS
CREATETABLE DROPTRANSLATION SETSESSION
COLLATION
CREATE
TRANSFORM
DROPTRIGGER SETTIMEZONE
CREATE
TRANSLATION
DROPTYPE SETTRANSACTION
CREATETRIGGER DROPVIEW SETTRANSFORM
GROUP
CREATETYPE EXECUTEIMMEDIATE STARTTRANSACTION
CREATEVIEW FETCH UPDATE
DEALLOCATE
DESCRIPTOR
Lesmotsréservés
En plus de ces commandes, un certain nombre d’autres mots ont unesignificationparticulièreenSQLetsontréservésàdesusagesspécifiques.Vous ne pouvez donc pas les employer pour nommer des variables ou àtoute autre fin. Vous comprendrez facilement pourquoi des tables, descolonnesoudesvariablesnepeuventporterdesnomsquicorrespondentàdesmots réservés. Imaginez quelle confusion une instruction telle que lasuivantepourraitinduire:
SELECTSELECTFROMSELECTWHERESELECT=WHERE;
L’AnnexeAcontientunelistecomplètedesmotsréservésdeSQL.
LestypesdedonnéesDifférentesimplémentationsdeSQLgèrentdifférentstypesdedonnées.LaspécificationSQL:2003reconnaîtsixtypesprédéfinisgénéraux:
» Lesnumériques.
» Lesbinaires.
» Leschaînes.
» Lesbooléens.
» Lesdates/heures.
» Lesintervalles.
» XML.
Chacun de ces types peut contenir plusieurs sous-types (les numériquesexacts,lesnumériquesapproximatifs,leschaînesdecaractères,leschaînesdebits,leschaînesd’objets).Enplusdecestypesprédéfinis,SQLgèrelescollections, les constructions et les types définis par l’utilisateur.Nous yreviendronsplusloindanscechapitre.
SivousutilisezuneimplémentationdeSQLquigèreunouplusieurstypesde données que la spécification SQL : ne mentionne pas, vous pouvezrendrevotrebasededonnéesplusportable en évitantd’y recourir.Avantquevousnedécidiezdecréeretd’utiliserdestypesdedonnéesdéfinispar
l’utilisateur, assurez-vous que tous les SGBD que vous pourriez vouloirgéreràl’avenirsupportentaussicestypes.
LesnumériquesexactsCommevous l’aurez probablement deviné d’après leur nom, les types dedonnéesnumériquesexactsvouspermettentd’exprimerexactementlavaleurd’unnombre.Cinqtypesdedonnéestombentdanscettecatégorie:
» INTEGER
» SMALLINT
» BIGINT
» NUMERIC
» DECIMAL
LetypededonnéesINTEGERUnedonnéede type INTEGERn’apasdepartiedécimaleet saprécisiondépend de chaque implémentation spécifique de SQL. En tant quedéveloppeur, vous ne pouvez donc pas spécifier la précision que voussouhaitez.
Laprécisiond’unnombreestlaquantitédebitssurlaquellecenombreestcodé.
LetypededonnéesSMALLINTLe type de données SMALLINT sert aussi pour les entiers, mais laprécision accordée à SMALLINT sur une implémentation spécifique nepeut dépasser celle de INTEGER sur cette même version. Lesimplémentations pour systèmes IBM/370 représentent généralement lesSMALLINTetlesINTEGERrespectivementàl’aidede16etde32bits.Bien souvent, les précisions de SMALLINT et de INTEGER sont lesmêmes.
Sivousdéfinissezunecolonned’unetabledebasededonnéescommeétantunedonnéeentièreetquevoussavezquelaplagedesvaleursdelacolonnene dépassera jamais la précision du type de données SMALLINT pourl’implémentationquevousutilisez,vouspouvezalorsutilisercetypeplutôtqueINTEGER.CelapermettraàvotreSGBDd’économiserdelaplace.
LetypededonnéesBIGINTBIGINT se définit comme étant un type dont la précision est au moinsaussi grande que INTEGER. Bien entendu, cette précision dépend del’implémentation.
LetypededonnéesNUMERICLe type de données NUMERIC permet de représenter des nombres quicomportent une partie décimale. Vous pouvez spécifier et la précision etl’échelle de la donnéeNUMERIC (rappelez-vous que la précision est lenombremaximaldebitspossibles).
L’échelle d’un nombre est la quantité de chiffres que comporte sa partiedécimale.L’échelled’unnombrenepeutêtreninégativeniplusgrandequelaprécisiondecenombre.
Si vous spécifiez le type de donnéesNUMERIC, votre implémentation deSQL vous donnera exactement le nombre de bits et l’échelle que voussouhaitez. Vous pourriez spécifier simplement NUMERIC et utiliserl’échelleetlaprécisionpardéfaut,ouNUMERIC(p)etdéfiniralorslaprécisionquevousdemandezetl’échellepardéfaut,ouencoreNUMERIC(p, e) et spécifier la précision et l’échelle que vous souhaitez. Lesparamètres p et e sont à remplacer par les valeurs que vous souhaitezutiliser.
Supposons par exemple que la précision par défaut du type de donnéesNUMERICde votre implémentation de SQL soit 12 et que l’échelle pardéfautsoit6.Sivousassignezàunecolonnedelabasededonnéesletypede données NUMERIC, la colonne pourra contenir des nombres dont lavaleur n’excédera pas 999 999,999999. Si vous spécifiez le type dedonnéesNUMERIC(10)pourcettecolonne,lacolonnepourracontenir
desnombresdont lavaleurnedépasserapas9999,999999.Leparamètre(10)spécifie laquantitémaximaledechiffrespossibledans lenombre.SivousspécifiezletypededonnéesNUMERIC(10,2),cettecolonnepourracontenirdesnombresdontlavaleurn’excéderapas99999999,99.Danscecasvousdisposeztoujoursde10chiffresmaisdeuxseulementsontdédiésàlapartiedécimale.
Les données NUMERIC sont à utiliser pour stocker des nombres telsque595,72.Cettevaleurauneprécisionde5(lenombretotaldechiffres)et une échelle de 2 (la quantité de chiffres qui se trouvent à droite de lavirgule). Le type de donnéesNUMERIC(5,2)permet de définir un telnombre.
LetypededonnéesDECIMALLe type de données DECIMAL est semblable au type de donnéesNUMERIC. Il peut aussi disposer d’une partie décimale et vous pouvezspécifier sa précision et son échelle. La seule différence est que laprécision que votre implémentation lui accorde peut être plus grande quecellequevousaurezspécifiée.Danscecas,c’estlaplusgrandeprécisionqui sera utilisée. Si vous ne spécifiez ni précision ni échelle,l’implémentation utilise ses valeurs par défaut, exactement comme elle lefaitpourletypeNUMERIC.
UnélémentquevousspécifiezcommeétantunNUMERIC(5,2)nepeutjamais contenir un nombre dont la valeur est supérieure à 999,99. Unedéfinition tellequeDECIMAL(5,2)permet toujours d’enregistrer desnombresdont lavaleurpeutaller jusqu’à999,99,maisaussidesnombresplusgrandsencoresil’implémentationlepermet.
Utilisez le typeNUMERICouDECIMAL si votre donnée comporte unepartie décimale, et choisissez les typesSMALLINT etINTEGER si ladonnée est un nombre entier. Adoptez le typeNUMERIC si vous voulezmaximiserlaportabilité,carunevaleurdontvousdéfinissezletypecommeNUMERIC (5,2) occupera exactement la même place sur tous lessystèmes.
LesnumériquesapproximatifsCertaines quantités peuvent prendre des valeurs dans une plage si grandequ’un ordinateur offrant une taille d’enregistrement fixe ne pourraitreprésenter ces valeurs exactement (cette taille peut être par exemplede 32 bits, 64 bits ou encore 128 bits). L’exactitude n’est alors plusnécessaireetuneapproximationdevientacceptable.SQLdéfinittroistypesdedonnéesnumériquesapproximatifspourtraitercegenredevaleur.
LetypededonnéesREALLe type de donnéesREALvous permet de stocker des nombres à virguleflottanteensimpleprécision,cettedernièredépendantdel’implémentation,qui est elle-même liée au matériel que vous utilisez. Par exemple, laprécisionest(évidemment)plusimportantesurunemachine64bitsquesurunsystème32bits.
Un nombre à virgule flottante est un nombre qui comporte une partiedécimale.Lapartiedécimale«flotte»,c’est-à-direqu’ellepeutapparaîtreàn’importequelendroitdanslenombre.3,14et3,14159sontdesexemplesdenombresàvirguleflottante.
LetypededonnéesDOUBLEPRECISIONLe type de donnéesDOUBLEPRECISION vous permet de stocker unnombre à virgule flottante en double précision, cette dernière dépendanttoujours de l’implémentation. La signification du mot DOUBLE dépendaussi de l’implémentation (étonnant, non ?). L’arithmétique en doubleprécision est utilisée par les scientifiques. Différentes disciplinesscientifiques ont divers besoins en terme de précision. Certainesimplémentations de SQL s’adressent plus à une catégorie particulièred’utilisateurs,tandisqued’autressontdestinéesàunpublicdifférent.
Surcertainssystèmes,letypeDOUBLEPRECISIONoccupeexactementdeux foisplusdeplaceque le typeREAL, tantpour lamantissequepourl’exposant. (Vous pouvez représenter n’importe quel nombre sous formed’unemantissemultipliéepar dix élevé à la puissancede l’exposant.Parexemple, vous pouvez écrire 6,626 sous la forme 6,626 E 3. Le
nombre 6,626 est la mantisse que vous multipliez par dix élevé à lapuissancedel’exposant,c’est-à-dire3danscetexemple.)
Vousnetirezaucunbénéficeàreprésenterdesnombresdontlesvaleurssonttrèsproches lesunesdesautres(parexemple6,626et6,626001)à l’aided’untypededonnéesapproximatif.Cependant,vousdevezutiliseruntypededonnéesapproximatifpourstockerlesnombresdontlavaleurestprochede zéro ou bien plus grande que un tel que 6626 E -34 (un très petitnombre).Lestypesnumériquesexactsnepermettentpasdestockerdetelsnombres.D’autressystèmesreprésententletypeDOUBLEPRECISIONàl’aided’unemantissedeuxfoisplusgrandeetd’unexposantpresquedeuxfois plus grand que la mantisse et l’exposant du type REAL. D’autressystèmes encore représentent le type DOUBLE PRECISION à l’aided’une mantisse deux fois plus grande et d’un exposant ayant la mêmecapacité que le type REAL. La précision est alors doublée, mais pasl’intervalle.
La spécification SQL n’essaie pas d’arbitrer les débats ou d’imposer lasignification deDOUBLEPRECISION. Elle indique simplement que laprécisiond’unnombreDOUBLEPRECISIONdoit être plus grandequecelled’unREAL.Cettecontraintepeutparaîtrequelquepeusuccincte,maiselle tient compte de la grande diversité des matériels que l’on peutrencontrer et représente donc probablement le meilleur compromispossible.
LetypededonnéesFLOATLe type de données FLOAT est à utiliser si vous pensez faire un jourmigrervotrebasededonnéesd’uneplate-formematérielleversune autredontlatailledesregistresestdifférente.LetypededonnéesFLOATvouspermetde spécifier laprécision,commeparexempledansFLOAT(5).Votresystèmeutiliseralasimpleprécisionouladoubleprécisionsuivantcequerequiertcequevousavezspécifié.
UtiliserletypeFLOATplutôtquelestypesDECIMALouREAL faciliteleportagedevotrebasededonnéesd’unmatériel à un autre, car il vouspermet de spécifier la précision. Les précisions de DECIMAL et deFLOATdépendentpourleurpartdumatériel.
Sivousn’êtespascertaindutypenumériqueexact(NUMERIC/DECIMAL)oudutypenumériqueapproximatif(FLOAT/REAL)quevousdevezutiliser,définissez toujours un type numérique exact. Les types de donnéesnumériquesexactsconsommentmoinsderessourcessystèmeet,commeilsedoit,permettentdestockerdesvaleursexactes(plutôtqu’approximatives).Vous devriez être en mesure de déterminer à l’avance si la plage desvaleurs que peut prendre une donnée est telle que vous n’avez d’autresolutionqued’utiliseruntypededonnéesnumériqueapproximatif.
LeschaînesdecaractèresLes bases de données permettent aujourd’hui de stocker des types dedonnéestrèsvariés,dontdesimages,dessonsetdesanimations.Bientôtceserapeut-être lesodeurs.Quelplaisirsivouspouviezhumer lapizzaquevous vous apprêtez à commander via Internet…Mais, dans la vraie vied’aujourd’hui,lestypesdedonnéeslesplusutiliséssontlesnombresetleschaînesdecaractères.
Ilexistetroisprincipauxtypesdedonnéescaractères:
» Leschaînesdelongueurfixe(CHARACTERouCHAR).
» Leschaînesdelongueurvariable(CHARACTERVARYINGou
VARCHAR).
» Lesobjetslargesdetypecaractère(CHARACTERLARGE
OBJECTouCLOB).
Vous pouvez aussi disposer de trois variantes de ces types de donnéescaractères:
» NATIONALCHARACTER.
» NATIONALCHARACTERVARYING.
» NATIONALCHARACTERLARGEOBJECT.
LetypededonnéesCHARACTER
Si vous définissez une colonne comme étant de type CHARACTER ouCHAR,vouspourrez spécifier lenombredecaractèresqu’ellecontientenutilisant lasyntaxeCHARACTER(x),oùx est la longueurde la chaîne.Par exemple, si vous indiquez que le type de données d’une colonne estCHARACTER(16),lalongueurmaximaledesdonnéesquevouspourrezysaisirserade16caractères.Sivousnespécifiezaucunargument(c’est-à-dire,sivousnefournissezaucunevaleuràlaplacedex),SQLsupposeraquelalongueurquevoussouhaitezestdeun(1)caractère.
SivoussaisissezunedonnéedansunchampCHARACTERd’une longueurspécifiée, et que cette donnée comporte moins de caractères que n’enprécisevotretype,SQLrempliral’espacerestantàl’aidedeblancs.
LetypededonnéesCHARACTERVARYINGLe type de données CHARACTER VARYING est utilisé si la taille desentrées d’une colonne peut varier,mais que vous ne voulez pas queSQLcomplète les chaînes à l’aide d’espaces. Ce type vous permet donc destocker le nombre exact de caractères que l’utilisateur aura saisis. Iln’existepasdevaleurpardéfautpourcetypededonnées.Pourledéfinir,utilisezlaformeCHARACTERVARYING(x)ouVARCHAR(x),oùxestlenombremaximaldecaractèresquevousautorisez.
LetypededonnéesCHARACTERLARGEOBJECTLe type de données CHARACTER LARGE OBJECT (CLOB) a étéintroduitdansSQL:1999.Commesonnomle laisseentendre, ilestutilisépourstockerdeschaînesdecaractèresimmenses,tropgrandespourletypeCHARACTER. Les CLOB ressemblent à des chaînes de caractèresclassiques, mais leur utilisation est soumise à un certain nombre derestrictions.
UnCLOBnepeutêtreutilisédansunprédicatPRIMARYKEY,FOREIGNKEYouUNIQUE. De plus, il ne peut être utilisé dans une comparaisonautre que l’égalité ou l’inégalité. Parce qu’ils sont très grands, lesapplications ne transfèrent généralement pas lesCLOBdans une base dedonnées. Un client spécial nommé localisateur CLOB est utilisé pour
manipulerlesdonnéesCLOB.C’estunparamètredontlavaleuridentifieunobjetlargedetypecaractère.
Unprédicatestunecommandequipeutêtresoitvraie,soitfausse.
LestypesdedonnéesNATIONALCHARACTER,NATIONALCHARACTERVARYINGetNATIONALCHARACTERLARGEOBJECTCertains langages utilisent des caractères qui leur sont spécifiques. Parexemple,l’allemand(commed’ailleurslefrançais)possèdedescaractèresspéciauxquin’existentpasenanglais.Quelqueslangagestelsquelerusseutilisent un jeu de caractères totalement différent de l’anglais. Même sil’anglaisestlejeudecaractèrespardéfautdevotresystème,vouspourrezquand même utiliser des jeux de caractères étrangers, car les types dedonnées NATIONAL CHARACTER, NATIONAL CHARACTER
VARYINGetNATIONALCHARACTERLARGEOBJECTfonctionnentcomme les types de donnéesCHARACTER,CHARACTERVARYING etCHARACTERLARGEOBJECT,àceciprèsquelejeudecaractèresquevous spécifiez peut être différent du jeu de caractères défini sur votresystème. Il est possible de spécifier le jeu de caractères quand vousdéfinissez la colonne d’une table. Si vous le voulez, SQL vous permetd’attribuerunjeudecaractèresdifférentàchaquecolonne.Dansl’exemplesuivant,nouscréonsunetablequiutilisedifférentsjeuxdecaractères:
CREATETABLETRADUCTION(
LANGAGE_1CHARACTER(40),
LANGAGE_2CHARACTERVARYING(40)CHARACTERSET
GREEK,
LANGAGE_3NATIONALCHARACTER(40),
LANGAGE_4CHARACTER(40)CHARACTERSETKANJI
);
LacolonneLANGAGE_1contientdescaractèresdujeudecaractèrespardéfaut de l’implémentation. La colonne LANGAGE_3 correspond auxcaractères du jeu de caractères national de l’implémentation. La colonneLANGAGE_2est destinée à contenir des caractères grecs. Et la colonneLANGAGE_4contiendradescaractèreskanji.Aprèsune longueabsence,lesjeuxdecaractèresasiatiques,telsquelekanji,sontdenouveauprésentsdanslesSGBD.
LeschaînesbinairesLestypesdedonnéeschaînesBINARYontété introduitsdansSQL:2008.Comme les données binaires sont fondamentales depuis l’ordinateurAtanasoff-Berrydesannées1930,cettereconnaissancedeleurimportancesemble assez tardive dans SQL (mais mieux vaut tard que jamais, jesuppose). Il existe trois différents types de données binaires : BINARY,BINARYVARYING,etBINARYLARGEOBJECT.
LetypededonnéesBINARYSivousdéfinissezletypededonnéesd’unecolonnecommeBINARY,vouspourrez spécifier le nombre d’octets que la colonne peut contenir enutilisant la syntaxe BINARY(x), où x est le nombre en question. Parexemple, si vous spécifiez BINARY (16), la chaîne binaire peutcomprendre16octets.Lesdonnéesbinairesdoivent être saisiesoctet paroctet,encommençantparlepremieroctet.
LetypededonnéesBINARYVARYINGUtilisezletypeBINARYVARYINGlorsquela longueurdelachaîneestvariable. Pour spécifier ce type de données, utilisez la forme BINARYVARYING(x) ou VARBINARY(x), où x est le nombre maximumd’octetspermis.Latailleminimaledelachaînebinaireestzéroetsataillemaximaleestx.
LetypededonnéesBINARYLARGEOBJECT
Le typededonnéesBINARYLARGEOBJECT (BLOB) estutilisépourd’énormeschaînesbinairesquisonttropgrandespourletypeBINARY.Lesfichiers d’images et de musiques sont des exemples. Les BLOBs secomportent beaucoup comme des chaînes binaires, mais SQL impose uncertainnombrederestrictionsàleurmanipulation.
En particulier, vous ne pouvez pas utiliser un BLOB comme prédicatPRIMARYKEY,FOREIGNKEYouUNIQUE.Deplus,ilestimpossiblede comparer desBLOBs autrement que pour l’égalité ou l’inégalité. LesBLOBs sont énormes, si bien que les applications ne les transfèrent pasd’unebasededonnées.EllesutilisentuntypededonnéesclientparticuliernommélocalisateurdeBLOBpourmanipuler lesdonnéesd’unBLOB.Celocalisateurestunparamètredontlavaleuridentifierlegrosobjetbinaire.
LesbooléensLe type de donnéesBOOLEAN comprend les valeurs vrai (true), faux(false)etinconnu(unknown).SiunbooléendontlavaleurestvraioufauxestcomparéàNULLouàlavaleurinconnu,lerésultatseralavaleurinconnu.
LesdatesetlesheuresLe standard SQL définit cinq types de données différents pour gérer lesdatesetlesheures.Cependantcestypesserecoupenttantlesunslesautresquecertainesimplémentationsnelesgèrentpastous.
Les implémentationsquinesupportentpas lescinq typesdedonnéespourlesdatesetlesheurespeuventvousposerdesproblèmessivoustentezdemigrervosbasesdedonnéessurunautresystème.Sicelaarrive,vérifiezque les implémentations sourceetdestination représentent lesdates et lesheuresdelamêmemanière.
LetypededonnéesDATELe typededonnéesDATEmémorise l’année, lemois et le jour, dans cetordre.L’annéeestunnombredequatrechiffres,lemoisetlejoursontdes
nombres à deux chiffres. Une valeur DATE peut représenter n’importequelle date depuis l’année 0001 jusqu’à l’année 9999. La longueur deDATEestde10positions,commedans1957-08-14.
LetypededonnéesTIMEWITHOUTTIMEZONELetypededonnéesTIMEWITHOUTTIMEZONEmémoriselesheures,lesminutesetlessecondes.Lesheuresetlesminutesutilisentchacunedeuxchiffres. Les secondes peuvent occuper deux chiffres, mais elles peuventaussi comporter une partie décimale. Il est donc possible dereprésenter9heures32minuteset58,436secondessouslaforme09:32:58.436.
Laprécisionde lapartiedécimaledépendde l’implémentation,mais elleest d’aumoins six chiffres.Une valeurTIMEWITHOUTTIMEZONEoccupehuitpositions(encomprenant lesdeux-points)quand lavaleurn’aaucune partie décimale ou neuf positions (en comprenant le séparateurdécimal)plus la taillede lapartiedécimalequand lavaleurencomporteune. Vous pouvez spécifier le type de donnéesTIMEWITHOUTTIMEZONEcommeTIME,cequicorrespondàuneheuresanspartiedécimale,oucommeTIMEWITHOUTTIMEZONE(p),oùpest le nombre dechiffresqu’occupelapartiedécimale.Dansl’exempleprécédent,letypededonnéesutiliséestTIMEWITHOUTTIMEZONE(3).
LetypededonnéesTIMESTAMPWITHOUTTIMEZONELetypededonnéesTIMESTAMPWITHOUTTIMEZONEstockeladateet l’heure.Les longueurs ainsi que les restrictions appliquées auxvaleursdesdonnéesTIMESTAMPWITHOUTTIMEZONEsontlesmêmesquepourDATEetTIMEWITHOUTTIMEZONE,àunedifférenceprès:lalongueur par défaut de la partie décimale de l’heure d’uneTIMESTAMPWITHOUTTIMEZONEestdesixchiffresetnondezéro.
Si la valeur n’a pas de partie décimale, la longueur de TIMESTAMPWITHOUTTIMEZONEestde19positions:dixpositionspourladate,
unespacequitientlieudeséparateurethuitpositions,danscetordre.Silavaleur a une partie décimale (six chiffres par défaut), la longueur estde 20 positions plus le nombre de chiffres de la partie décimale. Lavingtièmepositionestoccupéeparleséparateurdécimal.Vousspécifiezletype d’un champ comme TIMESTAMP WITHOUT TIME ZONE enutilisant soitTIMESTAMPWITHOUTTIMEZONE soit TIMESTAMPWITHOUTTIMEZONE(p),oùpestlenombredechiffresdelapartiedécimale. La valeur de p ne peut être négative, et l’implémentationdéterminesavaleurmaximale.
LetypededonnéesTIMEWITHTIMEZONELe type de données TIME WITH TIME ZONE est identique au typeTIMEWITHOUTTIMEZONE,àceciprèsqu’ilcontientuneinformationsupplémentaire : un décalage horaire par rapport au temps universel(autrementditparrapportauméridiendeGreenwichouGMT).Lavaleurde ce décalage peut aller de – 12 : 59 à + 13 : 00. Cette informationsupplémentaireoccupesixpositionsaprèsletemps:unséparateur,unsigneplus ou moins, puis le décalage en heures (deux chiffres) et en minutes(deux chiffres) séparées par un deux-points. Une valeur TIME WITHTIMEZONE sans partie décimale (par défaut) occupe 14 positions. Sivousspécifiezunepartiedécimale,lalongueurestde15positionspluslenombredechiffresquevousaurezallouéàcettepartiedécimale.
LetypededonnéesTIMESTAMPWITHTIMEZONELe type de données TIMESTAMP WITH TIME ZONE fonctionneexactementcommeletypeTIMESTAMPWITHOUTTIMEZONE,àceciprès qu’il contient lui aussi un décalage horaire. Cette informationsupplémentaireoccupesixpositions.Lalongueurtotaled’uneTIMESTAMPWITHTIMEZONE passe donc à 25 positions sans partie décimale età26positionspluslenombredechiffresallouésàlapartiedécimalesielleencomporte.
Lesintervalles
Lestypesdedonnéesintervallessontapparentésauxtypesdedonnéesdateet heure.Un intervalle est la différence entre deux valeurs date et heure.Dansdenombreusesapplicationsquimanipulentdesdates,desheuresoulesdeuxà la fois,vousavezparfoisbesoindedéterminer l’intervallequiséparedeuxdatesoudeuxheures.
SQLreconnaîtdeuxtypesdistinctsd’intervalles:année-moisetjour-heure.Lepremierreprésentel’écartenannéesetmoisentredeuxdates.Lesecondcorrespondàladifférenceenjours,heures,minutesetsecondesentredeuxinstantsd’unmêmemois.Iln’estpaspossibledemélangerlesdeuxdansuncalcul,carlalongueurdesmoisvarie(28,29,30ou31jours).
LetypeXMLLe type de données prédéfiniXML est le petit dernier de la famille. Lesdonnées XML ont une structure arborescente, ce qui signifie qu’un nœudracine peut avoir plusieurs nœuds enfants, chacun étant à son toursusceptibledeposséder sapropredescendance. IntroduitdansSQL:2003,le typeXMLa été enrichi dans SQL/XML : 2005. L’édition 2005 définitcinq sous-types paramétrés en plus du type d’origine. Les valeurs XMLpeuvent être des instances de deux ou plusieurs types, car certains sous-types sont eux-mêmes des sous-types d’autres sous-types (peut-êtrefaudrait-il les désigner par sous-sous-types, voire sous-sous-sous-types ;fortheureusement,SQL:2008définitunstandardpourseréférerauxsous-types).
LesmodificateursprimairesdutypeXMLsontSEQUENCE,CONTENTetDOCUMENT. Les modificateurs secondaires sont UNTYPED, ANY etXMLSCHEMA.LaFigure2.1montrelastructurearborescentequiillustrelesrelationsentrelessous-types.
FIGURE2.1Lesrelationsentrelessous-typesXML.
Voyons brièvement les types XML que vous vous devez de connaître.Commençonsparlestypesdebasepourterminerparlespluscomplexes:
» XML(SEQUENCE):ToutevaleurXMLestsoitunevaleur
SQLNULL,soituneséquenceXQuery.Decettemanière,
chaquevaleurXMLestuneinstancedutype
XML(SEQUENCE).XQueryestunlangagederequête
spécifiquementconçupourextrairedesinformationsà
partirdedonnéesXML.Ils’agitdutypeXMLleplusbasique.
» XML(SEQUENCE)estlemoinsrestrictifdestypesXML.Il
peutaccepterdesvaleursquinerespectentpastotalement
lescanonsXML.Lesautrestypessont,quantàeux,
sensiblementmoinsconciliants.
» XML(CONTENT(ANY)):Ils’agitd’untypelégèrementplus
restrictifqueXML(SEQUENCE).ChaquevaleurXMLquiest
soitunNULL,soitunnœuddedocumentXQuery(ouun
enfantdecenœud)estuneinstancedecetype.Toute
instancedeXML(CONTENT(ANY))estégalementune
instancedeXML(SEQUENCE).Lesvaleursdutype
XML(CONTENT(ANY))nesontpasnécessairement
conformesauxcanonsXML.Ilpeuts’agirdesrésultats
intermédiairesd’unerequêtequiserontparlasuiteremis
enbonneetdueforme.
» XML(CONTENT(UNTYPED)):Cetypeestencoreplus
restrictifqueleprécédent.Parconséquent,toutevaleurdu
typeXML(CONTENT(UNTYPED))estaussiuneinstance
destypesXML(CONTENT(ANY))etXML(SEQUENCE).
ToutevaleurXMLquiestsoitlavaleurnulle,soitunevaleur
nonnulledetypeXML(CONTENT(ANY)),estunnœudd’un
documentXQueryD,telquecequisuitestvraipourtout
nœudélémentcontenudansl’arbreTdontlaracineestD:
• Lapropriététype-nameestxdt:untyped.
• LapropriéténilledestFalse.
• PourtoutnœudattributcontenudansT,la
propriéténameestxdt:untypedAtomic.
• PourtoutnœudattributcontenudansT,la
propriététypeestunevaleurdetype
XML(CONTENT(UNTYPED)).
» XML-(CONTENT(XMLSCHEMA)):C’estlesecondsous-
typedeXML(CONTENT(ANY))avec
XML(CONTENT(UNTYPED)).ToutevaleurXMLquiestsoitla
valeurnulle,soitunevaleurnonnulledetype
XML(CONTENT(ANY))estaussiunnœudd’undocument
XQueryD,telquetoutnœudélémentcontenudansl’arbre
TderacineD:
• EstvalideconformémentauschémaXMLS,ou
• Estvalideconformémentàl’espacedenomsNdans
leschémaS,ou
• Estvalideconformémentàladéclarationde
schémaEdansunschémaXMLS,ou
• Estunevaleurdetype
XML(CONTENT(XMLSCHEMA)),dontledescripteurde
typecomprendceluiduschémaSet,siNest
spécifié,l’URIdel’espacedenomsdeN,ousiEest
spécifié,l’URIdel’espacedenomsdeEetleNCName
deE.
» XML(DOCUMENT(ANY)):Ils’agitd’uneautrevariantedu
typeXML(CONTENT(ANY))avecunerestriction
supplémentaire:uneinstancedeXML(DOCUMENT(ANY))
estunnœuddedocumentpossédantexactementun
élémentenfant,zéroouplusieursnœudscommentaires,et
zéroouplusieursnœudsd’instructionsdetraitement
XQuery.
» XML(DOCUMENT(UNTYPED)):Chaquevaleurquiestsoit
lavaleurNULL,soitunevaleurnonnulledetype
XML(CONTENT(UNTYPED))quisetrouvedansunnœud
documentdontlapropriétéchildrencomprend
exactementunnœudélément,zéroouplusieursnœuds
commentaires,etzéroouplusieursinstructionsde
traitementXQuery,estunevaleurdetype
XML(DOCUMENT(UNTYPED)).Touteslesinstancesde
XML(DOCUMENT(UNTYPED))sontégalementdes
instancesdutypeXML(CONTENT(UNTYPED)).Cesont
égalementdesinstancesdutypeXML(DOCUMENT(ANY)).
XML(DOCUMENT(UNTYPED))estleplusrestrictifdetous
lessous-types.End’autrestermes,lesrestrictionsdes
autressous-typess’appliquentégalementàlui.Tout
documentqualifiécommeétantun
XML(DOCUMENT(UNTYPED))estaussiuneinstancede
touslesautressous-typesXML.
LestypesROWLe typededonnéesROWa été introduit dansSQL:1999. Il n’estpas trèsfaciledecomprendresonusage,etilsepeutqu’entantqu’utilisateurnoviceou intermédiairedeSQLvousn’ayez jamaisàvousenservir.Après tout,lesgenss’ensontbienpassésentre1986et1999.
Une des principales caractéristiques du type de données ROW est qu’ilviolelesrèglesdenormalisationénoncéesparE.F.Coddàl’aubedesbasesdedonnéesrelationnelles.JereviendraisurcesrèglesdansleChapitre5.L’unedes caractéristiquesde la première formenormale est qu’un champd’une ligned’une tablenepeut contenir plusieursvaleurs.Unchampdoitdoncrecevoiruneetuneseulevaleur.Cependant,letypededonnéesROWvouspermetdedéclarerqu’unelignededonnéestoutentièreseracontenuedans un seul champ d’une seule ligne. En d’autres termes, il est possibled’insérerunelignedansuneligne.
Lesformesnormales,selonleDrCodd,définissentlescaractéristiquesdesbasesdedonnéesrelationnelles.L’inclusiondutypeROWdanslestandardSQLaétélapremièretentatived’extensiondumodèlerelationnelpur.
Considérezl’instructionSQLsuivante,quidéclarel’adressed’unepersonnesouslaformed’untypeROW:
CREATEROWTYPEtype_adresse(
RueCHARACTERVARYING(25)
VilleCHARACTERVARYING(20)
EtatCHARACTER(2)
Code_PostalCHARACTERVARYING(9)
);
Une fois défini, le nouveau typeROW peut être utilisé dans la définitiond’unetable:
CREATSSSETABLECLIENTS(
ClientIDINTEGERPRIMARYKEY,
PrénomCHARACTERVARYING(25),
NomCHARACTERVARYING(20),
Adressetype_adresse
TéléphoneCHARACTERVARYING(15)
);
Toutl’intérêtest icidepouvoirdéfiniruneetuneseulefoiscequ’estuneadresse et de pouvoir réutiliser cette définition dans la déclaration dediversestables:tabledeclients,tabledesemployés,etc.
LestypesCollectionUnefoisleprocessusdetransgressiondesrèglesintangiblesdeSQLentaméavecSQL:1999, la définition de types violant la première formenormaleest devenue possible. Un champ peut donc dès lors contenir une pleinecollectiond’objetsetnonplusuneseuleetuniqueentité.LetypeARRAYaété introduit avec SQL:1999, et le type MULTISET a été ajouté dansSQL:2003.
Deuxcollectionsnepeuventêtrecomparéesquesiellesont lemêmetype(soit ARRAY, soit MULTISET) et si les types de leurs éléments sontcomparables. Du fait que les tableaux comportent un nombre définid’entrées,ilestpossibledecomparerlesélémentscorrespondants.Cen’estpas lecasdesMULTISET,mais la comparaison reste faisable si (a)uneénumérationexistepourchaquemultisetconcerné,etsi(b)lesénumérationspeuventêtreappariées.
LetypeARRAYComme le type ROW, le type de données ARRAY viole lui aussi lapremière forme normale (1NF), mais d’une manière différente. Le type
ARRAY est une collection, pas un type distinct comme le sont les typesCHARACTERouNUMERIC.Pourl’essentiel,untypeARRAYpermetàunautretypedeprendreplusieursvaleursquiserontmémoriséesdansunseulchampd’unetable.
Supposons par exemple que votre entreprise désire pouvoir contacter sesclientsàtoutinstant,qu’ilssoientautravail,àleurdomicileousurlaroute.Voussouhaiteriezdoncstockerplusieursnumérosdetéléphonepourchaquepersonne.Vouspouvezlefaireendéclarantl’attributTéléphonesouslaformed’untableaudelamanièresuivante:
CREATETABLECLIENTS(
ClientIDINTEGERPRIMARYKEY,
NomCHARACTERVARYING(25),
PrénomCHARACTERVARYING(20),
Adressetype_adresse
TéléphoneCHARACTERVARYING(15)
);
LanotationARRAY[3]vouspermetdestocker jusqu’à troisnumérosdetéléphone dans la table CLIENTS. Ce type de données enfreint lesrestrictions imposées par le Dr Codd quand il énonça les règles denormalisation en préférant l’intégrité des données à la flexibilité de leurgestion. SQL:1999 a rendu la gestion des données plus souplemais rendaussileurstructurepluscomplexe.
Pluslastructuredevientcomplexe,plusvousdevezprendregardequesonutilisation remette en cause l’intégrité de votre base de données. Il estnécessairedemesureravecprécisionleseffetsdechaqueactionquevouseffectuezsurvotrebasededonnées.Untableauestordonnédanslesensoùchacunde seséléments est associéavecexactementunepositionordinaledansledittableau.
Si la cardinalité d’un tableau est inférieure au maximum déclaré, lescellules inutilisées dans le tableau sont considérées comme inexistantes.Elles ne sont pas considérée comme contentant des valeurs nulles ; ellesn’existenttoutsimplementpas.
Vous pouvez accéder aux éléments spécifiques d’un tableau en faisantfigurerleurindexentrecrochets.SivousavezuntableaunomméTéléphone,alors Téléphone[3] vous permet de vous référer au troisième élémentfigurantdanscetableau.
DepuisSQL:1999,ilestpossibledetrouverlacardinalitéd’untableaueninvoquant la fonction CARDINALITY. Depuis SQL:2011, vous pouvezdécouvrir la cardinalité maximale d’un tableau en utilisant la fonctionARRAY_MAX_CARDINALITY.Cette fonctionest trèsutile,carellevouspermet d’écrire des routines de portée générale qui s’appliquent à destableaux de cardinalités maximales différentes. Les routines où lacardinalitémaximaleestcodéeendurnes’appliquentqu’auxtableauxdelacardinalité maximale correspondante, et doivent donc être réécrites pours’appliqueràdestableauxdecardinalitésmaximalesdifférentes.
AlorsqueSQL:1999aintroduitletypededonnéesARRAYetlapossibilitéd’adresser les éléments spécifiques d’un tableau, rien n’a été prévu poursupprimer des éléments du tableau. Cet oubli a été corrigé dansSQL:2011 avec l’introduction de la fonction TRIM_ARRAY, qui vouspermetdesupprimerdesélémentsàlafind’untableau.
LetypeMULTISETUnmultiset est une collectionnonordonnée.Des éléments spécifiquesdumultiset peuvent ne pas être référencés, car ils ne sont affectés à aucunepositionordinaleparticulière.
LestypesREFLes typesREF ne font pas partie du noyau de SQL.Cela signifie qu’unSGBD peut se proclamer compatible avec le standard SQL sansimplémenter les typesREF. Il ne s’agit pasd’un typededonnéesdistinctcomme le sont CHARACTER et NUMERIC. C’est un pointeur vers unedonnée,untypededonnéesouuntypededonnéesabstraitquirésidedansuneligned’unetable(unsite).Déréférencerlepointeurpermetderetrouverlavaleurstockéedanslesitecible.
Sivousn’ycomprenez rien,nevous inquiétezpas,carvousn’êtespas leseul. L’utilisation des typesREF requiert une connaissance avancée desprincipesde laprogrammationorientéeobjet.Ce livresegarderabiende
plongerdanslesarcanesdecesujet.Enfait,puisquelestypesREFnefontpaspartieducœurdeSQL,vousferiezmieuxdevousenpasser.Sivoussouhaitez restercompatibleavecunmaximumdeplates-formesdeSGBD,tenez-vous-enauxfonctionnalitésdunoyaudeSQL.
Lestypesdéfinisparl’utilisateurLestypesdéfinisparl’utilisateur(UDT,pourUser-DefinedTypes)ontétéintroduits avec SQL:1999. Ils viennent du monde de la programmationorientée objet (POO). En tant que programmeur SQL, vous n’êtes pluslimitéparlestypesdedonnéesdéfinisdanslaspécificationstandard.Vouspouvez définir vos propres types de données en vous basant sur lesprincipesdestypesdedonnéesabstraites(ADT,pourAbstractDataTypes)courantsdansleslangagesorientésobjettelsqueleC++.
L’undesprincipaux intérêtsdesUDTestqu’ilspeuvent êtreutiliséspourgérer le problème de compatibilité entre SQL et le langage « emballé »autourdeSQL.UnproblèmerécurrentdeSQLestquesestypesdedonnéesprédéfinis ne sont pas forcément les mêmes que ceux employés par leslangagesdanslesquelsdesinstructionsSQLsontintégrées.GrâceauxUDT,leprogrammeurd’unebasededonnéespeutcréerdansSQLdes typesdedonnéesquicorrespondentexactementauxtypesdulangagequ’ilutilise.
UnUDTencapsuledesattributsetdesméthodes.Lemondeextérieurvoitles attributs et les résultats produits par les méthodes, maisl’implémentationspécifiquedecesméthodesluiestcachée.Ilestpossibled’imposer des restrictions sur l’accès aux attributs et auxméthodes d’unUDTenspécifiantqu’ilssontpublics,privésouprotégés.
» Lesattributs(oulesméthodes)publicssontaccessibles
àtouslesutilisateursdel’UDT.
» Lesattributs(oulesméthodes)privésnesont
accessiblesqu’àl’UDTlui-même.
» Lesattributs(oulesméthodes)protégésnesont
accessiblesqu’àl’UDTlui-mêmeouàsestypesdérivés.
Vous voyez qu’unUDT de SQL se comporte pour l’essentiel comme uneclasse dans un langage de programmation orienté objet. Il existe deux
formes de types définis par l’utilisateur : les types distincts et les typesstructurés.
LestypesdistinctsLes types distincts sont les plus élémentaires des types définis parl’utilisateur. Ils prennent la forme d’un type de donnée unique et sontconstruits à partir d’un des types prédéfinis (appelés dans ce cas typessource). Plusieurs types distincts qui sont tous basés sur un même typesource sont différents les uns des autres et ne sont donc pas directementcomparables. Par exemple, vous pouvez utiliser des types distincts pourreprésenterdiversesmonnaies:
CREATEDISTINCTTYPEDollarUSASDECIMAL(9,2);
créeunnouveautypededonnéespourlesdollars,basésurletypeprédéfiniDECIMAL.Vouspouvezensuiteajouterunautretypedistinctdelamanièresuivante:
CREATEDISTINCTTYPEEuroASDECIMAL(9,2);
Ilestmaintenantpossiblededéfinirdestablesquiutilisentcestypes:
CREATETABLEFactureUS(
FacIDINTEGERPRIMARYKEY,
ClientIDINTEGER,
EmpIDINTEGER,
TotalVenteDollarUS,
TaxeDollarUS,
PortDollarUS,
GrandTotalDollarUS
);
CREATETABLEFactureEuro(
FacIDINTEGERPRIMARYKEY,
ClientIDINTEGER,
EmpIDINTEGER,
TotalVenteEuro,
TaxeEuro,
PortEuro,
GrandTotalEuro
);
LetypeDollarUSetletypeEurossonttouslesdeuxbaséssurletypeDECIMAL, mais leurs instances ne peuvent être directement comparéesentreellesniavecdesinstancesdutypeDECIMAL.Danslaréalité, ilestpossible de convertir en SQL des dollars US en euros à l’aide d’unopérateurspécial(CAST).Unefoislaconversioneffectuée,lacomparaisondevientpossible.
TypesstructurésLa seconde forme de type défini par l’utilisation (le type structuré) estexpriméeàl’aided’unelisted’attributsetdeméthodesaulieud’êtrebaséesurununiquetypesourceprédéfini.
Constructeurs
LorsquevouscréezunUDTstructuré,leSGBDluiassocieautomatiquementune fonction dite constructeur qui prend le même nom que cet UDT. Letravail du constructeur consiste à initialiser les attributs de l’UDT à leurvaleurpardéfaut.
Mutateursetaccesseurs
Toujourslorsdelacréationd’unUDTstructuré,leSGBDajoutetoutaussiautomatiquement deux autres fonctions : un mutateur et un accesseur. Unmutateur, lorsqu’il est invoqué, change la valeur d’un attribut du typestructurécorrespondant.Àl’inverse,unaccesseursertàretrouverlavaleurd’unattributdansuntypestructuré.Vouspouvezincluredesaccesseursdansdes instructions SELECT afin de récupérer des valeurs dans une base dedonnées.
Sous-typesetsupertypes
Ilpeutexisterunerelationhiérarchiqueentredeuxtypesstructurés.Prenonsun exemple. Un type appelé MusiqueCDudt possède un sous-typedénomméRockCDudtetunautredénomméClassiqueCDudt.Parrapportàcesdeuxstylesmusicaux,MusiqueCDudtest leursupertype.RockCDudtest un sous-type propre de MusiqueCDudt s’il n’existe aucunintermédiaireentreeux,autrementditquelquechosequisoitàlafoissous-typedeMusiqueCDudtetsupertypedeRockCDudt.Si,maintenant,oncréeun sous-type de RockCDudt appelé HeavyMetalCDudt, ce dernierseraparhéritageunsous-typedeMusiqueCDudt,maispasunsous-typepropre.Voussuiveztoujours?
Exempledetypestructuré
VouspouvezcréerdesUDTstructurésdelamanièresuivante:
/*CréeunUDTappeléMusiqueCDudt*/
CREATETYPEMusiqueCDudtAS
/*Spécifielesattributs*/
TitreCHAR(40),
CoutDECIMAL(9,2),
PrixConseilleDECIMAL(9,2),
/*Lessous-typessontautorisés*/
NOTFINAL;
CREATETYPERockCDudtUNDERMusiqueCDudtNOT
FINAL;
Le sous-type RockCDudt hérite des attributs du supertypeMusiqueCDudt.
CREATETYPEHeavyMetalCDudtUNDERRockCDudt
FINAL;
Maintenantquevousavezles types, ilestpossibledecréer les tablesquilesutilisent.Parexemple:
CREATETABLEMETALSKU(
AlbumHeavyMetalCDudt,
SKUINTEGER);
Iln’yaplusqu’àajouterdeslignesàlatable:
BEGIN
/*Déclareunevariabletemporairea*/
DECLAREa=HeavyMetalCDudt;
/*Exécutelafonctionconstructeur*/
SETa=HeavyMetalCDidt();
/*Exécutelapremièrefonctionmutateur*/
SETa=a.Titre(‘EdouardtheGreat’);
/*Exécuteladeuxièmefonctionmutateur*/
SETa=a.Cout(7.5);
/*Exécutelatroisièmefonctionmutateur*/
SETa=a.PrixConseille(15.99);
INSERTINTOMETALSKUVALUES(a,31415926);
END
Lestypesdéfinisparl’utilisateurpourlestypesCollectionDans la sectionprécédente «Typesdistincts », je vous aimontré commecréeruntypedéfiniparl’utilisateuràpartird’untypeprédéfini,enutilisantl’exemple de la création du type USDollar à partir du type Euros. Cettepossibilité a été introduite dans SQL:1999. SQL:2011 l’étend en vouspermettant de créer un nouveau type défini par l’utilisateur à partir d’untype Collection. Cela permet au développeur de définir des méthodess’appliquant à un tableau comme un tout, et non plus à chacun de seséléments,commel’imposaitSQL:1999.
Listedestypesdedonnées
LeTableau2.2contient la listedesdivers typesdedonnées,chacunétantaccompagnéd’unexemple.
TABLEAU2.2Lestypesdedonnées.
Typededonnées Exemple
CHARACTER(20) ‘RadioAmateur’
VARCHAR(20) ‘RadioAmateur’
CLOB(1000000) ‘Cettechaînedecaractèresfaitun
milliondecaractères…’
SMALLINT,BIGINT
ouINTEGER
7500
NUMERICou
DECIMAL
3425.432
REAL,FLOATou
DOUBLEPRECISION
6.626E-34
BLOB(1000000) ‘1001001110101011010101010101…’
BOOLEAN ‘true’
DATE DATE‘1957-08-14’
TIME(2)WITHOUT
TIMEZONE1
TIME‘12:46:02.43’WITHOUTTIME
ZONE
TIME(3)WITH
TIMEZONE
TIME‘12:46:02.432-08:00’
WITHTIMEZONE
TIMESTAMPWITHOUT
TIMEZONE(0)
TIMESTAMP
TIMESTAMP‘1957-08-1412:46:02’
WITHOUTTIMEZONE
Typededonnées Exemple
TIMESTAMPWITH
TIMEZONE(0)
TIMESTAMP
TIMESTAMP‘1957-08-1412:46:02-
08:00’WITHTIMEZONE
INTERVALDAY INTERVAL‘4’DAY
XML(SEQUENCE) <Client>AllenG.Taylor</Client>
ROW ROW(RueVARCHAR(25),Ville
VARCHAR(20),EtatCHAR(2),Code_
PostalVARCHAR(9))
ARRAY INTEGERARRAY[15]
MULTISET Aucunlittéralnes’appliqueautypeMULTISET
REF Pasuntypemaisunpointeur
USERDEFINEDTYPE TypedemonnaiebasésurDECIMAL
L’argumentspécifielenombredechiffresdelapartiedécimale.
VotreimplémentationspécifiquedeSQLpeutnepassupportertouslestypesde données qui viennent d’être décrits dans cette section. De plus, il estpossiblequevotreimplémentationutilisedestypesdedonnéesnonstandardquejenedécrispasici.
LesvaleursnullesSi un champd’unebase de données contient une donnée, ce champa unevaleurspécifique.Unchampquinecontientaucunedonnéeestditavoirunevaleurnulle(NULL).N’oubliezpasque:
» Dansunchampnumérique,unevaleurnullen’apasla
mêmesignificationquezéro.
» Dansunchampcaractère,unevaleurnullen’estpasun
caractèreespace.
Le zéro numérique et le caractère espace sont des valeurs définies. Unevaleurnulleindiquequelavaleurduchampn’estpasdéterminée.
Un champ peut prendre une valeur nulle dans de nombreux cas. Voiciquelquesexemples:
» Lavaleurexistemaisvousnelaconnaissezpas
encore.VouspassezMASSEànuldanslaligneTopdela
tableQUARKavantquelamasseduquarknesoit
déterminée.
» Lavaleurn’existepasencore.VousdéfinissezTOTAL_
VENDUcommeétantnuldanslaligneSQLpourLesNuls
delatableLIVRES,carvousnesavezpasencorecombien
d’exemplairesontétévendus.
» Lechampn’estpasutilisablepourcetteligne
particulière.VousaffectezàSEXEunevaleurnulledansla
rangéeZ6POdelatableEMPLOYES,carZ6POestun
droïde.
» Lavaleuresthorsdeportée.Vousattribuezlavaleur
nulleàRICHESSEdanslarangéeBILLGATESdelatable
FORTUNES,carlemaximumpossiblede999999999euros
estlargementdépassé.
Un champ peut prendre une valeur nulle pour de nombreuses raisons.Netirezpasdesconclusionshâtivessurlasignificationd’unevaleurnulle.
LescontraintesLescontraintessontdesrestrictionsquevousappliquezsurlesdonnéesquequelqu’unpeutsaisirdanslabasededonnées.Parexemple,si lesentréesd’unecertainecolonnenumériquedoiventapparteniràunecertaineplagedevaleurs.Siquelqu’un tentede saisirunevaleurquin’appartientpas à cet
intervalle, la base de données risque d’être contaminée. Vous pouvezprévenircettenuisanceenappliquantunecontraintedeplageàlacolonne.
Généralement,unprogrammequiutiliseunebasededonnéesappliquedescontraintes à cette base. Cependant, les SGBD les plus récents vouspermettentd’imposerdirectementdescontraintesàvosbases.Celaprésenteplusieurs avantages. Si plusieurs applications utilisent la même base dedonnées, vous n’aurez à appliquer les contraintes qu’une seule fois. Deplus, ajouterdescontraintesauniveaude labasededonnéesest toujoursplussimplequedelesintégrerdansuneapplication.Dansdenombreuxcas,ilsuffitd’ajouteruneclauseàvotreinstructionCREATE.
Je décrirai en détail les contraintes et les assertions (qui sont descontraintesquevousappliquezàplusieurstables)dansleChapitre5.
UtiliserSQLsurunsystèmeclient/serveur
SQLestunsous-langagededonnéesquifonctionnesurunsystèmeisoléousur un systèmemulti-utilisateur. SQL est particulièrement efficace sur lessystèmes client/serveur. Sur de tels systèmes, les utilisateurs de plusieursmachinesclientsquiseconnectentàlamachineserveurpeuventaccéderàunebase de données au travers d’un réseau local (LAN)oude tout autremoyen de communication. Le programme qui fonctionne sur la machineclientcontientlescommandesSQLdemanipulationdedonnées.Laportiondu SGBD qui réside côté client envoie les commandes au serveur via lemoyen de communication qui les relie. Sur l’autre versant, la portionserveurduSGBD interprète et exécute les commandesSQL,puis renvoielesrésultatsauclient.VouspouvezencoderdesopérationstrèscomplexesenSQLsurleclient,puislesfairedécoderetexécutersurleserveur.Celapermetdesurcroîtd’économiserdelabandepassante.
Si vous récupérez les données en utilisant SQL sur un systèmeclient/serveur, seules les données que vous demandez transitent via lesupportdecommunicationquirelieleclientauserveur.Àl’inverse,surunsystème se contentant de partager des ressources et qui n’utilise qu’unserveurdotéd’uneintelligenceminimale,desvolumesdedonnéesénormesdoiventcirculersurleréseaupourquevouspuissiezrécupérerlesdonnéesdontvousavezbesoin.Ilest inutiledepréciserquecegenred’opérationsralentitconsidérablementlesopérations(toutenaccroissantlesfaillesdans
lasécurité).L’architectureclient/serveurcombinéeàSQLpermetd’obtenirdebonnesperformancessurtouslestypesderéseaux.
LeserveurTantqu’ilnereçoitpasderequêteduclient,leserveurnefaitrien.Ilnefaitqu’attendre.Siplusieursclients luiprésententdes requêtessimultanément,leserveurdoityrépondreimmédiatement.Ildiffèredesmachinesclientsence qu’il dispose d’un vaste espace de stockage disque. Le serveur estoptimisé pour accéder rapidement aux données. Et comme il doit gérerbeaucoupderequêtessimultanées,ilabesoind’unprocesseurrapide,voiremêmedeplusieursprocesseurs.
Cequ’estleserveurLeserveur(abréviationpourserveurdebasededonnées)estlapartied’unsystèmeclient/serveurquicontientlabasededonnées.Onytrouveaussilecôté serveur du SGBD. Cette partie du SGBD interprète les commandesémanantdesclientset lestraduitenopérationssurlabasededonnées.Lelogiciel serveur formate aussi les résultats des requêtes et renvoie lesrésultatsauclientquil’ademandé.
CequefaitleserveurLe travail du serveur est relativement simple et évident. Tout ce qu’unserveurdoitfaireestdelire,interpréteretexécuterlescommandesquedesclients luienvoientpar le réseau.Cescommandessont rédigéesdans l’undesnombreuxsous-langagesdedonnées.
Unsous-langagenedéfinitpascomplètementunlangage:ilenimplémenteseulementunepartie.Unsous-langagededonnéesnetraitequedelagestiondesdonnées.Cesous-langagecontientdesopérationspourinsérer,mettreàjour, supprimer et sélectionner des données, mais il ne dispose pasd’instructionsdecontrôledeflux tellesque lesbouclesDO, lesvariableslocales, les fonctions, lesprocéduresou lesopérationsd’entrée/sortie surlesimprimantes.SQLestlepluscourantdessous-langagesdedonnées.Lesautres sous-langagesdedonnéespropriétairesont été supplantésparSQLsurtouslestypesdemachines.DepuisSQL:1999,SQLaacquisnombredesfonctionnalités qui manquent aux sous-langages de données traditionnels.
Cependant, il n’est pas encore devenu un langage de programmationgénéraliste à part entière, et il doit pour cette raison être combiné à unlangagehôtepourréaliserdesapplicationsdebasesdedonnées.
LeclientLa partie client d’un système client/serveur consiste en un composantmatériel et un composant logiciel. Le composantmatériel est l’ordinateurclientetsoninterfaceauréseaulocal.Leclientmatérielpeutparfaitementêtre identique au matériel serveur. Ce qui distingue le client du serveur,c’estlelogiciel.
Cequ’estleclientLerôleprincipalduclientconsisteàfourniruneinterfaceutilisateur.Pourautant que l’utilisateur est concerné, la machine client est l’ordinateur etl’interface utilisateur est l’application. L’utilisateur peut ne même pasréaliser qu’un processus se déroule sur un serveur. Le serveur estgénéralementhorsdesavue(dansuneautrepièce,dansunautrebâtiment,àl’autre bout de la planète…). Hormis l’interface utilisateur, le clientcontientaussi leprogrammed’applicationet lapartieclientduSGBD.Leprogramme d’application effectue les tâches spécifiques que vous luidemandez, commesaisirdes fichesdepayeoudescommandes.Lapartieclient duSGBDexécute les commandes de ce programmeet échangedesdonnées etdes commandesSQLdemanipulationdedonnées avec le côtéserveurduSGBD.
CequefaitleclientLe client affiche l’information à l’écran et répond aux informations quel’utilisateurtransmetvialeclavier,lasourisoutoutautrepériphérique.Leclient peut aussi traiter des données qui proviennent d’autres postes duréseau(quellequesoitparailleurslanaturephysiquedecelui-ci).LapartieclientduSGBDeffectuetoutletravailde«réflexion».C’estdonccellequiintéresse le plus le développeur. La partie serveur ne fait que traiter lesrequêtesqueluiprésenteleclientd’unemanièremécanique,répétitive.
UtiliserSQLsurl’Internetouun
intranetLagestiondesbasesdedonnéesviaInternetouunintranetestradicalementdifférente de la gestion via un système client/ serveur classique. Toutd’abord, sur un système client/serveur traditionnel, l’essentiel desfonctionnalitésduSGBDrésidesurlamachineclient.Surunsystèmebasésur Internet, l’essentiel du SGBD se trouve sur le serveur. Le client peutn’héberger rien d’autre qu’un navigateur Web. Au mieux, il contient uneextension du navigateur, telle qu’un plug-in pourNetscape ou un contrôleActiveX. Par conséquent, la « masse critique » du système se trouvereportéesurleserveur.Celaprésenteplusieursavantages:
» Laportionclientdusystème(lenavigateur)estpeu
onéreuse.
» Vousdisposezd’uneinterfaceutilisateurstandardisée.
» Lamaintenanceduclientestfacile.
» Larelationclient/serveureststandardisée.
» Vouspossédezunsupporttoutàfaitcourantpourafficher
desdonnéesmultimédias.
Les principaux inconvénients que présente lamanipulation d’une base dedonnéesviaInternetsontlasécuritéetl’intégritédesdonnées:
» Pourprotégerl’informationdetoutealtérationou
consultationparuntiersnonautorisé,leserveurWebetle
clientdoiventsupporterunetechniquepuissantede
cryptage.
» Lesnavigateursneprocèdentpasàdevéritablescontrôles
devalidationdesdonnéessaisies.
» Lestablesdelabasededonnéesquirésidentsurplusieurs
serveurspeuventsedésynchroniser.
Lesextensionsclientetserveurconçuespourgérercesproblèmesontfaitd’Internetunearchitecturepour laquelle ilestpossiblededévelopperdesapplications de base de données. L’architecture d’un intranet ressemble àcelle d’Internet, mais la sécurité pose un moindre problème. Commel’organisationquiassurelamaintenancedel’intranetdisposed’uncontrôlephysiquesurlesmachinesclients,lesserveursetleréseauquilesrelie,unintranet est bien moins exposé aux attaques des pirates. Cependant, lesproblèmesducontrôledes informations saisiesetde ladésynchronisationdemeurent.
S
Chapitre3LescomposantsdeSQL
DANSCECHAPITRE:
» Créerdesbasesdedonnées.
» Manipulerdesdonnées.
» Protégerlesbasesdedonnées.
QLestunlangageconçupourlacréationetlamaintenancedesdonnéesdans des bases relationnelles. Quoique les vendeurs de systèmes degestiondebasesdedonnéesrelationnellesutilisent leurpropreversion
de SQL, un standard ISO/ANSI (révisé en 2011) définit ce qu’est SQL.Toutes les implémentations s’écartent plus ou moins de cette norme. Parconséquent, s’en tenir au standard est la meilleure tactique pour fairefonctionnerunebasededonnéessurplusd’uneplate-forme.
Bien que SQL ne soit pas vraiment un langage de programmation, il estquandmêmedotédequelquesoutils impressionnants.Trois langagespourle prix d’un vous permettent de créer, de modifier, de maintenir et desécuriserunebasededonnéesrelationnelle:
» Lelangagededéfinitiondedonnées(DDL,pourData
DefinitionLanguage):C’estlapartiedeSQLquevous
utilisezpourcréer(définircomplètement)unebasede
données,modifiersastructureetladétruirequandvous
n’enavezplusbesoin.
» Lelangagedemanipulationdedonnées(DML,pour
DataManipulationLanguage):Ilpermetlamaintenance
d’unebasededonnées.Enutilisantcepuissantoutil,vous
pouvezspécifierexactementcequevousvoulezfaireavec
lesdonnéesdevotrebasededonnées:lesentrer,les
modifieroulesextraire.
» Lelangagedecontrôlededonnées(DCL,pourData
ControlLanguage):Unearmurepourprotégervos
données.Quandilestutilisécorrectement,DCLpermetde
sécuriservotrebasededonnées;laqualitédecette
protectiondépenddel’implémentation.Sivotre
implémentationnefournitpasuneprotectionsuffisante,
vousdevezhausserleniveaudecelle-cidansvotre
programmed’application.
CechapitreprésenteDDL,DMLetDCL.
Lelangagededéfinitiondedonnées(DDL)
Lelangagededéfinitiondedonnées(DDL)estunepartiedeSQLquevousutilisezpourcréer,modifieroudétruire lesélémentsdebase(c’est lecasde le dire) d’une base de données relationnelle. Il s’agit des tables, desvues,desschémas,descatalogues,desclustersetéventuellementd’autreschoses. Dans cette section, je présente la hiérarchie qui lie tous cesélémentsainsiquelescommandesquipermettentdelesmanipuler.
DansleChapitre1,j’aiparlédestablesetdesschémasenprécisantqu’unschémaestunestructuregénéralequicontientdes tables.Lestableset lesschémassontdoncdeuxélémentsdelahiérarchieducontenud’unebasededonnéesrelationnelle.Vouspouvezdécomposercettehiérarchieainsi:
» Lestablescontiennentdeslignesetdescolonnes.
» Lesschémascontiennentdestablesetdesvues.
» Lescataloguescontiennentdesschémas.
Labasededonnéeselle-mêmecontientdescatalogues.Vousverrezqu’ondésigneparfoislabasededonnéesparletermecluster.
«Yaqu’à!»estunmauvaisconseilSupposonsquevoussoyezchargédecréerunebasededonnéespourvotresociété.Excitéàl’idéedecréerunestructureutile,valable,bienconçueetde grande importance pour le futur, vous prenez place devant votreordinateuretcommencezàsaisirdescommandesSQLCREATE.Correct?
Ehbiennon!C’estenfaitlameilleuresolutionpouraboutiraudésastre.Denombreux projets de développement de bases de données partent dans lemur dès le départ parce que l’excitation l’emporte sur une planificationrigoureuse.Mêmesivousavezuneidéetrèsprécisedelastructuredevotrebasededonnées,vousdeveztoutécrirenoirsurblancavantdetoucherleclavierdevotreordinateur.
Ledéveloppementdebasesdedonnéespeutassezbienêtrecomparéaujeud’échecs.Dansunecompétitiond’échecs,voustrouvezundéplacementquivousparaîtbon.Lapenduletourne, la tensionfaitsonœuvre,et l’urgencede jouer ce coup vous étreint.Mais il y a une forte probabilité pour quevous ayez manqué quelque chose. Les GM (Grands Maîtres) conseillentsouventauxdébutantsdes’asseoirsurleursmains.Etcen’estqu’àmoitiéuneplaisanterie.Siplacervosmainssousvoscuissesvousévitedejoueruncoupmalcalculé,alorsc’estlebongesteàfaire.Sivousprenezunpeuplusdetempspourétudierlaposition,vouspourreztrouveruncoupencoremeilleur (ou découvrir l’attaque foudroyante que vous réserve votreadversaire).De lamêmemanière,plongerdans lacréationd’unebasededonnéessansuneréflexionpréalablesuffisanteconduitpresque toujoursàunestructurequi,dans lemeilleurdescas,seramaloptimisée.Etconduitdroitaudésastredanslepiredescas(commeuneinvitationàlacorruptiondes données lancée aux quatre vents). Certes, s’asseoir sur vosmains nevous aidera pas à avancer. Prendre un stylo dans une de ces mains etcommenceràplanifiersurpapierleschémadevotrebasededonnées,si.
Lalistesuivanterecensequelquesprocéduresquevousdevezconserveràl’espritquandvousplanifiezvotrebasededonnées:
» Identifieztouteslestables.
» Définissezlescolonnesquechaquetabledoitcontenir.
» Attribuezunecléprimaireuniqueàchaquetable(jeparle
desclésdanslesChapitres4et5).
» Assurez-vousquechaquetabledelabasededonnées
partageaumoinsunecolonneavecuneautretable.Ces
colonnespartagéesserventàétablirdeslienslogiques
entrel’informationcontenuedansunetableetune
informationcorrespondantedansuneautretable.
» Passezchaquetabledanslatroisièmeformenormale
(3NF)oupluspourprévenirtouteanomaliepouvantêtre
engendréeparuneinsertion,unesuppressionouunemise
àjour(jetraitedelanormalisationdesbasesdedonnées
dansleChapitre5).
Quandvousaurez terminévotreconception sur lepapier,vouspourrez latransférer sur l’ordinateur à l’aide de la commande SQL CREATE. Plusvraisemblablement, vous utiliserez l’interface graphique utilisateur (GUI)du SGBD pour cela. Si vous utilisez votre GUI, votre SGBD convertiratoutesvosactionsenSQL«danslescoulisses».
CréerdestablesUnetabled’unebasededonnéesestuntableauàdeuxdimensionscomposéde lignes et de colonnes. Vous pouvez créer une table en utilisant lacommandeSQLCREATETABLE.Vousspécifiezenparamètrelenometletypededonnéesdechaquecolonne.
Unefoisquevousavezcréélatable,vousallezystockerdesdonnées(cequiestunefonctiondeDMLetnondeDDL).Sivosbesoinsévoluent,vouspouvezmodifier la structurede la table enutilisant la commandeALTERTABLE.S’ilarriveunjourquelatablenesoitplusutile,ilestpossibledel’éliminer en utilisant la commande DROP. Les différentes formes descommandesCREATEetALTER,ainsiquelacommandeDROP,constituentlelangagededéfinitiondedonnéesdeSQL.
Imaginonsquevousêtesleconcepteurd’unebasededonnéesetquevousnevoulez plus que vos tables dégénèrent à cause demises à jour répétées.Vousdécidezalorsdestructurerlestablesdevotrebasededonnéesselonlameilleureformenormalepourpréserverl’intégritédesdonnées.
Lanormalisation(c’estàelleseuleunvastesujetd’études)estunemanièrede structurer les tables d’une base de données pour que lesmises à journ’introduisent pas d’anomalies.Chaque table que vous créez contient descolonnes qui correspondent à des attributs qui sont étroitement liés entreeux.
Par exemple, vous pouvez créer une table CLIENTS avec les attributsCLIENT_ID,NOM,PRENOM,RUE,VILLE,ETAT,CODE_POS-TALetTELEPHONE.Touscesattributssontplusétroitement liésà l’entitéclientqu’à toute autre entité d’une base de données qui contient parfois denombreuses tables. Ces attributs représentent toutes les informationspermanentesquevousconservezsurvosclients.
Laplupartdessystèmesdegestiondebasesdedonnéesdisposentd’unoutilgraphique pour créer des tables de bases de données. Cependant, vouspouvez aussi créer des tables en utilisant une commandeSQL.L’exemplesuivantvousmontrecommentcréerunetableCLIENTSdecettemanière:
CREATETABLECLIENTS(
CLIENT_IDINTEGERNOTNULL,
PRENOMCHARACTER(15),
NOMCHARACTER(20)NOTNULL,
RUECHARACTER(25),
VILLECHARACTER(20),
ETATCHARACTER(2),
CODE_POSTALINTEGER,
TELEPHONECHARACTER(13));
Vousprécisezpourchaquecolonnesonnom(parexemple,CLIENT_ID),son type de données (par exemple,INTEGER) et éventuellement une ouplusieurscontraintes(parexemple,NOTNULL).
La Figure 3.1 vousmontre une portion de la table CLIENTS remplie dequelquesdonnées.
FIGURE3.1LatableCLIENTScrééeenutilisantlacommandeCREATETABLE.
Sil’implémentationdeSQLquevousutiliseznerépondpascomplètementaustandardANSI/ISO,lasyntaxequevousdevrezutiliserpeutdifférerdecellequej’utilisedanscelivre.ConsultezladocumentationdevotreSGBDpourplusd’informationsàcesujet.
ChambreavecvueUnjour,vousaurezbesoinderécupérerdesdonnéesdelatableCLIENTS.Vousnevoudrezpasvisualisertout,maissimplementquelquescolonnesetquelqueslignes.Vousaurezalorsbesoind’unevue.
Unevueest une table virtuelle. Sur la plupart des implémentations, unevue n’a aucune existence physique indépendante. La définition de la vueexistedanslesmétadonnéesdelabase,maissesdonnéesproviennentdelatableoudes tablesdontvousdérivezcettevue.Lesdonnéesde lavuenesont donc pas physiquement dupliquées quelque part sur le disque.Certaines vues contiennent des colonnes et des lignes spécifiques d’uneseule table. D’autres, les vues multitables, proposent des données quiproviennentdeplusieurstables.
VueavecuneseuletableLaréponseàvosquestionssetrouveparfoisdansuneseuletabledevotrebase de données. Dans ce cas, vous pouvez créer une vue simple. Parexemple,supposonsquevousdésiriezconsulterlesnomsetlesnumérosdetéléphone de tous les clients américains qui vivent dans l’État du NewHampshire.VouscréezunevueàpartirdelatableCLIENTSenutilisantlacommandeSQLsuivante:
CREATEVIEWNH_CLIENTAS
SELECTCLIENTS.PRENOM,
CLIENTS.NOM,
CLIENTS.TELEPHONE
FROMCLIENTS
WHERECLIENTS.ETAT=‘NH’;
La Figure 3.2 vous montre comment la vue est dérivée de la tableCLIENTS.
FIGURE3.2VousdérivezlavueNH_CLIENTdelatableCLIENTS.
Cecodeesttoutàfaitcorrect,maisvouspourriezarriveraumêmerésultatplusrapidementsil’implémentationdeSQLquevousutilisezprésumaitquetouteslesréférencesauxtablessontfaitesderrièrelaclauseFROM.Danscecas,vouspouvezréduirelacommandeàcesquelqueslignes:
CREATEVIEWNH_CLIENTAS
SELECTPRENOM,NOM,TELEPHONE
FROMCLIENTS
WHEREETAT=‘NH’;
Quoiquelasecondesyntaxesoitplusagréableàécrireetàlire,elleestplussensible aux effets d’une commande ALTER TABLE. Ces effets serontnégligeablesdansl’exemplequenousvenonsdevoir,carnotrevuen’utilisepasdejointure.Cependant,lesvuesquiutilisentJOINsontmoinsrobustessivousn’utilisezpasdesnomstotalementqualifiés.JetraitedesjointuresauChapitre11.
CréerunevuemultitableIlarrivesouventquevousdeviezextrairedesdonnéesdedeuxouplusieurstables pour répondre à une question. Par exemple, supposons que voustravailliezpourunmagasindesportetquevousdésiriezobtenirlalistedesclients qui ont acheté un équipement de ski l’année dernière pour leurenvoyer un mailing promotionnel. Vous aurez besoin d’informationscontenuesdanslestablesCLIENT,PRODUIT,FACTUREetLIGNE_FAC-TURE. Vous pouvez créer une vue multitable qui contienne toutes cesinformations.Une fois que vous aurez créé cette vue, elle tiendra comptedesmises à jour effectuées sur les tables depuis la dernière fois oùvousl’aurezconsultée.
Labasededonnéesdumagasindesportcontientquatre tables :CLIENT,PRODUITS,FACTUREetLIGNE_FACTURE.Ces tablessontstructuréescommelemontreleTableau3.1.
TABLEAU3.1Lestablesdumagasindesport.
Table Colonne Typededonnées Contrainte
CLIENT CLIENT_ID INTEGER NOTNULL
PRENOM CHARACTER(15)
NOM CHARACTER(20) NOTNULL
RUE CHARACTER(25)
VILLE CHARACTER(20)
ETAT CHARACTER(2)
CODE_POSTAL INTEGER
TELEPHONE CHARACTER(13)
PRODUIT PRODUIT_ID INTEGER NOTNULL
NOM CHARACTER(25)
DESCRIPTION CHARACTER(30)
CATEGORIE CHARACTER(15)
VENDEUR_ID INTEGER
NOM_VENDEUR CHARACTER(30)
FACTURE NUMERO_FACTURE INTEGERL NOTNUL
CLIENT_ID INTEGER
DATE_FACTURE DATE
TOTAL_VENTE NUMERIC(9,2)
TOTAL_REMIS NUMERIC(9,2)
FORME_PAIEMENT CHARACTER(10)
LIGNE_FACTURE NUMERO_LIGNE INTEGER NOTNULL
NUMERO_FACTURE INTEGER
PRODUIT_ID INTEGER
QUANTITE INTEGER
PRIX_VENTE NUMERIC(9,2)
NotezquequelquescolonnesduTableau3.1contiennentlacontrainteNOTNULL. Ces colonnes sont soit des clés primaires de leur table, soit descolonnesdontvousnevoulezpasqu’ellescontiennentunevaleurnulle.Lacléprimaired’unetableidentifiedemanièreuniquechaqueligne.Elledoitcontenirunevaleurnonnulle.JetraitedesclésdansleChapitre5.
Les tables sont reliées entre ellespardes colonnesqu’ellespossèdent encommun.LaFigure3.3illustrecesrelations.Ellessontdécritesci-dessous.
» LatableCLIENTentretientunerelation«unàplusieurs»
aveclatableFACTURE.Unclientpeuteffectuerplusieurs
achats,cequigénèreautantdefactures.Cependant,
chaquefacturen’estliéequ’àununiqueclient.
» LatableFACTUREentretientunerelation«unàplusieurs»
aveclatableLIGNE_FACTURE.Unefacturepeutcontenir
plusieurslignes,maischaquelignen’apparaîtquesurune
etuneseulefacture.
» LatablePRODUITentretientaussiunerelation«unà
plusieurs»aveclatableLIGNE_FACTURE.Unproduitpeut
apparaîtredansplusieurslignessuruneouplusieurs
factures.Cependant,chaquelignenepeutcorrespondre
qu’àununiqueproduit.
FIGURE3.3Lastructuredelabasededonnéesdumagasindesport.
» LatableCLIENTestreliéeàlatableFACTUREparla
colonneCLIENT_ID.LatableFACTUREestreliéeàlatable
LIGNE_FACTUREparlacolonneNUMERO_FACTURE.La
tablePRODUITestreliéeàlatableLIGNE_FACTUREparla
colonnePRODUIT_ID.
Ceslienssontl’essenced’unebasededonnéesrelationnelle.
Pourobtenirl’informationquevousrecherchezsurvosclients,vousaurezbesoindeNOM,PRENOM,RUE,VILLE,ETATetCODE_POS-TALdansla table CLIENT, de CATEGORIE dans la table PRODUIT et deNUMERO_FACTUREdanslaLIGNE_FACTURE.Vouspouvezcréerlavueenutilisantlescommandessuivantes:
CREATEVIEWSKI_CLIENT1AS
SELECTNOM,
PRENOM,
RUE,
VILLE,
ETAT,
CODE_POSTAL,
NUMERO_FACTURE
FROMCLIENTJOINFACTURE
USING(CLIENT_ID);
CREATEVIEWSKI_CLIENT2AS
SELECTNOM,
PRENOM,
RUE,
VILLE,
ETAT,
CODE_POSTAL,
PRODUIT_ID
FROMSKI_CLIENT1JOINLIGNE_FACTURE
USING(NUMERO_FACTURE);
CREATEVIEWSKI_CLIENT3AS
SELECTNOM,
PRENOM,
RUE,
VILLE,
ETAT,
CODE_POSTAL,
CATEGORIE
FROMSKI_CLIENT2JOINPRODUIT
USING(PRODUIT_ID);
CREATEVIEWSKI_CLIENTAS
SELECTDISTINCTNOM,
PRENOM,
RUE,
VILLE,
ETAT,
CODE_POSTAL,
FROMSKI_CLIENT3
WHERECATEGORIE=‘Ski’;
Ces instructionsCREATEVIEW combinent les données des différentestablesenutilisantl’opérateurJOIN.LaFigure3.4etlesnotesquisuiventdétaillentceprocessus.
» Lapremièreinstructioncombinelescolonnesdelatable
CLIENTavecunecolonnedelatableFACTUREpourcréerla
vueSKI_CLIENT1.
» Ladeuxièmeinstructioncombinelescolonnesdelatable
SKI_CLIENT1avecunecolonnedelatable
FACTURE_LIGNEpourcréerlavueSKI_CLIENT2.
» Latroisièmeinstructioncombinelescolonnesdelatable
SKI_CLIENT2avecunecolonnedelatablePRODUITpour
créerlavueSKI_CLIENT3.
FIGURE3.4Lacréationd’unevuemultitableenutilisantdesjointures.
» Laquatrièmeinstructionsupprimetoutesleslignesqui
n’entrentpasdanslacatégorie«ski».Lerésultatfinalest
unevue(SKI_CLIENT)quicontientlesnomsetles
adressesdetouslesclientsquiontachetéaumoinsun
produitdelacatégorie«ski».
LemotcléDISTINCTdanslaclauseSELECTdela
quatrièmeinstructionCREATEVIEWvousgarantitque
vousn’aurezqu’uneetuneseuleentréepourchaqueclient,
mêmesicertainsclientsontachetéplusieursarticlesde
ski.
Il est possible de créer une vuemultitable en une seule instruction SQL.Toutefois,sivouspensezquel’uneoul’autredescommandesprécédentessont complexes, imaginez quel degré de complexité atteindrait celle quicumuleraittoutesleursfonctions.Jepréfèrelasimplicitéàlacomplexité,sibienquechaquefoisquec’estpossible,jechoisislemoyenleplussimpled’accomplirunefonction,mêmesicen’estpastrès«efficient».
Organiserlestablesenschémas
Unetableestunensembledelignesetdecolonnesquitraitegénéralementd’entités d’un type spécifique telles que les clients, les produits ou lesfactures.Danslaréalité, il fautparfoismanipulerdes informationsliéesàplusieurs de ces entités. Sur le plan organisationnel, vous rassemblez lestablesquevousassociezàcesentitéspour formerunschémalogique (unschéma logique est la structure organisationnelle qui correspond à unensembledetablesliéesentreelles).
En plus des schémas logiques, la base de données contient des schémasphysiques.Leschémaphysiqueestlamanièredontladonnéeetsesobjetsassociés, tels que des index, sont physiquement organisés sur lespériphériquesdestockagedusystème.Quandjementionneleschémad’unebasededonnées,jemeréfèreauschémalogiqueetnonauschémaphysique.
Dansunsystèmeoùplusieursprojetsindépendantspeuventcoexister,vouspouvez assigner toutes les tables qui sont reliées entre elles à un seulschéma.Lesautresgroupesdetablesserontlecaséchéantplacésdansleurspropresschémas.
Vous devriez nommer les schémas pour vous assurer que personne nemélangera accidentellement les tables d’un projet avec celles d’un autreprojet. Chaque projet dispose de son propre schéma associé, que vousdistinguezdesautresparsonnom.Cependant,ilestfréquentquedestablesde différents projets portent le même nom (par exemple CLIENT ouPRODUIT). Pour lever toute ambiguïté, vous devriez désigner vos tablesdans vos instructions SQL en les préfixant par le nom de leur schéma(commedansNOM_SCHEMA.TABLE_NOM).Sivousnefournissezaucunnom de schéma, SQL considère que la table appartient au schéma pardéfaut.
OrdonnerparcatalogueUtiliserplusieurs schémaspeut se révéler insuffisantquand le systèmedegestion de bases de données est très volumineux. En effet, sur unenvironnement distribué de base de données quemanipulent de nombreuxutilisateurs,vouspouvezrencontrerdesschémasquiportentlemêmenom.Pour éviter que ce problème ne se pose, SQL a ajouté un élémentsupplémentaire dans la hiérarchie des conteneurs : le catalogue. Uncatalogueestunensemblenommédeschémas.
Vous pouvez qualifier le nom d’une table en utilisant le nom de soncatalogueetlenomdesonschéma.Celavousgarantitquelatableneserapasconfondueavecune tablehomonymed’unschémahomonyme.Lenomdetableainsiqualifiéprendralaformesuivante:
NOM_CATALOG.NOM_SCHEMA.NOM_TABLE
La hiérarchie des conteneurs d’une base de données comprend à sonsommet les clusters, mais rares sont les systèmes qui en requièrentl’utilisation. La plupart du temps, les choses s’arrêtent au catalogue. Uncatalogueregroupedesschémas,unschémaregroupedestablesetdesvues,lesquellessontconstituéesdecolonnesetdelignes.
Lecatalogueinclutaussi l’informationdeschéma.Cettedernièrecontientlestablessystème.Lestablessystèmegèrentlesmétadonnéesassociéesauxautresschémas.DansleChapitre1,j’aidéfiniunebasededonnéescommeunecollectiond’enregistrementsintégréscapabledesedécrireelle-même.Cesontlesmétadonnéescontenuesdanslestablessystèmequirendentcettedescriptionpossible.
Dufaitquelescataloguessontidentifiésparleurnom,ilestpossibled’enutiliserplusieursdansunebasededonnées.Chaquecataloguepeutcontenirplusieurs schémas, et chaque schéma peut contenir à son tour plusieurstables. Et, bien entendu, chaque table est susceptible de posséder demultiplescolonnesetdemultiples lignes.CesrelationshiérarchiquessontreprésentéessurlaFigure3.5.
FIGURE3.5Lastructurehiérarchiqued’unebasededonnéesSQL.
Sefamiliariseraveclescommandes
DDLLelangagededéfinitiondedonnées(DDL)permetdemanipulerlastructurede la base de données alors que DML, le langage de manipulation dedonnées, permetde traiter lesdonnées stockéesdans cette structure.SousSQL,DDLestcomposédetroiscommandes:
» CREATE:Vousutilisezlesdiversesformesdela
commandeCREATEpourcréerlesstructuresessentielles
delabasededonnées.
» ALTER:VousutilisezlacommandeALTERpourmodifier
lesstructuresquevousavezcréées.
» DROP:SivousutilisezlacommandeDROPsurunetable,
lacommandedétruitnonseulementlesdonnéesdela
tablemaisaussisastructure.
Danslessectionssuivantes,jevaisvousdonnerunedescriptionrapidedescommandes de DDL. Nous nous servirons de ces commandes dans lesexemplesdesChapitres4et5.
CREATELacommandeCREATEvouspermetdecréerdenombreuxobjetsdeSQLdont les schémas, les domaines, les tables et les vues. En utilisantl’instructionCREATESCHEMA, vous pouvez créer un schéma, identifiersonpropriétaireetspécifiersonjeudecaractèrespardéfaut.Parexemple:
CREATESCHEMAVENTES
AUTHORIZATIONRESPONSABLE_VENTES
DEFAULTCHARACTERSETASCII_FULL;
Utilisezl’instructionCREATEDOMAINpourappliquerdescontraintesàdes valeurs de colonne ou pour spécifier un ordre de regroupement. Lescontraintesquevousappliquezaudomainedéterminentlanaturedesobjetsquecedernieraledroitdecontenir.Vouspouvezcréerdesdomainesaprèsavoirdéfiniunschéma.Parexemple:
CREATEDOMAINAgeASINTEGER
CHECK(AGE>20);
Pour les tables, vous disposez de l’instruction CREATE TABLE. Etl’instructionCREATEVIEWsertcommeilsedoitàcréerdesvues.Ci-avantdanscechapitre,jevousaiprésentédesexemplesd’utilisationdecesdeux instructions. Quand vous utilisez CREATE TABLE pour créer unenouvelletable,vouspouvezsimultanémentspécifierdescontraintessurlescolonnesdecettedernière.
Cependant, il arrive que vous deviez définir des contraintes qui nes’appliquentpasàune tableenparticuliermaisà tout le schéma.Servez-vous alors de l’instruction CREATE ASSERTION pour définir cescontraintes.
Vous disposez aussi des instructions CREATE CHARACTER, CREATECOLLATION et CREATE TRANSLATION pour créer des jeux decaractères, des séquences d’interclassement et des tables de traduction.(Uneséquenced’interclassementdéfinit l’ordredanslequelvouseffectuezdes comparaisons et des tris. Les tables de traduction contrôlent laconversiondechaînesdecaractèresd’unjeudecaractèresàunautre.)
ALTERUne fois que vous aurez créé une table, il se peut que vous ayez à lamodifier.L’instructionALTERTABLEvousserviraàajouter,modifieretsupprimer des colonnes dans cette table. ALTER s’utilise aussi sur desdomaines.
DROPIlesttrèsfaciledesupprimerunetableduschémad’unebasededonnées.UtilisezsimplementlacommandeDROPTABLE.Celasupprimetouteslesdonnéesdelatableainsiquelesmétadonnéesquidéfinissentcettedernièredansledictionnairedesdonnées.
Lelangagedemanipulationde
données(DML)Comme je l’ai dit audébutde ce chapitre,DDLest lapartiedeSQLquipermetdecréer,modifieretdétruiredesstructuresdelabasededonnées.DDL ne manipule pas les données elles-mêmes. Ce rôle est dévolu aulangagedemanipulationdedonnées(DML).QuelquesinstructionsdeDMLsont faciles à comprendre, d’autres semblent souvent très complexes. Eneffet, si une instruction DML comprend plusieurs expressions, clauses,prédicatsousous-requêtes, ilpeutdevenir trèsdifficiledecomprendrecequ’elle signifie. Il est alors indispensable de découper l’instruction enmorceauxetd’étudierchacund’entreeux.
LesinstructionsDMLdontvousdisposezsontINSERT,UPDATE,DELETEetSELECT.Cesinstructionspeuventcomprendreplusieursparties,dontdemultiples clauses.Chaqueclausepeut à son tourcontenirdesexpressionsde valeurs, des connecteurs logiques, des prédicats, des fonctionsd’agrégation et des sous-requêtes. Toutes ces clauses vous permettent demieux extraire l’information de la base de données en discriminantprécisément les enregistrements qu’elle contient. Dans le Chapitre 6, jetraitedel’utilisationdescommandesdeDML.Jerentreraidansledétaildecelles-cidanslesChapitres8à14.
LesexpressionsdevaleursVous pouvez utiliser des expressions de valeurs pour combiner deux ouplusieurs valeurs. Il existe neuf sortes d’expressions de valeurs, chacunecorrespondantàuntypededonnéesprécis:
» Numérique.
» Chaîne.
» Dateetheure.
» Intervalle.
» Booléen.
» Définiparl’utilisateur.
» Ligne.
» Collection.
Les typesBooléen,Définipar l’utilisateuretLigneontété introduitsdansSQL:1999. Certaines implémentations ne les gèrent pas encore. Si vousvoulez utiliser ces types de données, vérifiez ce qu’en dit votreimplémentation.
LesexpressionsdevaleursnumériquesPour combiner des valeurs numériques, utilisez les opérateurs d’addition(+),desoustraction(-),demultiplication(*)etdedivision(/).Les lignessuivantescontiennentquelquesexemplesdetellesexpressions:
12–7
15/3-4
6*(8+2)
Lesvaleursquifigurentdanscetexemplesontdeslittérauxnumériques.Cesvaleurs pourraient tout aussi bien être des noms de colonnes, desparamètres,desvariableshôtesoudessous-requêtes.L’essentielestqu’ils’agissetoujoursdevaleursnumériques.Envoiciquelquesexemples:
SOUSTOTAL+TAXE+PORT
6*KM/HEURE
:mois/12
Ledeux-points(:)dudernierexemplesignalequeletermequisuit(mois)estsoitunparamètre,soitunevariablehôte.
LesexpressionsdechaînesLes expressions de chaînes peuvent inclure l’opérateur de concaténation(||). Utilisez la concaténation pour fusionner deux chaînes de caractères,commelemontreleTableau3.2.
TABLEAU3.2Exemplesdeconcaténationdechaînes.
Expression Résultat
‘renseignement‘
||‘militaire’
‘renseignementmilitaire’
‘tra’||‘duction’ ‘traduction’
VILLE||‘‘
||ETAT||‘
‘||CODE_POSTAL
Uneseulechaînecomposéedelaville,del’Étatet
ducodepostal,chacunétantséparéparunseul
espace.
Certaines implémentations de SQL utilisent l’opérateur + pour laconcaténation.Vérifiezcepointdansvotredocumentation.
Quelques implémentationspeuventproposerd’autresopérateursdechaînequelaconcaténation,maislestandardSQLnelessupportepas.
Lesexpressionsdevaleursdetypedate/heureetintervalleLesexpressionsdevaleursdate/heuremanipulentdesdatesetdesheures.DesdonnéesdetypeDATE,TIME,TIMESTAMPetINTERVALpeuventfigurerdanscesexpressions.Lerésultatd’uneexpressiondate/heureestuneautreexpressiondate/heure.Vouspouvezajouterousoustraireunintervalled’unedate/heureetspécifierdesinformationsrelativesaudécalagehoraire.
Voiciunexempled’utilisationd’unetelleexpression:
DATE_PRET+INTERVAL‘7’DAY
Unebibliothèquepourraitutiliseruneexpressiondecetypepourdéterminerquandenvoyerunenotederappelàunabonnépourqu’ilrapporteleslivresempruntés.L’exemplequisuitutilisecettefois-cil’heure:
TIME‘18:55:48’ATLOCAL
LemotcléATLOCALsignifiequel’heureestexpriméeentempsnational.
Les expressions de type intervalle évaluent le temps passé entre deuxdate/heure.Ilyadeuxtypesd’intervalles:année-moisetjour-heure.Vousnepouvezpaslesmélangerauseind’unemêmeexpression.
Parexemple,quelqu’unpourraitrendreunlivreà labibliothèqueaprèsladate limite. En utilisant une expression de type intervalle, vous pourriezcalculer combien de jours se sont écoulés depuis cette date butoir etcalculerl’amendecorrespondante:
(DATE_RETOUR-DATE_LIMITE)DAY
Commeun intervallepeut être soit de type année-mois, soit de type jour-heure,vousdevezpréciserqueltypevoussouhaitezutiliser.Dansl’exempleprécédent,j’aispécifiéDAY.
LesexpressionsdevaleursbooléennesUneexpressiondevaleurbooléennetestelavéracitéd’unprédicat.Voiciunexempled’expressionbooléenne:
(CLASSE=DOCTORANT)ISTRUE
S’il s’agissait d’une condition pour récupérer des lignes d’une table quirecensedesétudiants,seulescellesquicorrespondentàdesdoctorantsvousseraient retournées. Pour obtenir les enregistrements de tous ceux qui nesontpasdoctorants,vouspourriezutiliser:
NOT(CLASSE=DOCTORANT)ISTRUE
Cequipeutaussis’écrire:
(CLASSE=DOCTORANT)ISFALSE
Voici comment récupérer toutes les lignes dont la colonne CLASSEcontientunevaleurnulle:
(CLASSE=DOCTORANT)ISUNKNOWN
Lesexpressionsdevaleursdetypedéfini
parl’utilisateurLes types définis par l’utilisateur sont décrits dans le Chapitre 2. Cettefonctionnalité permet aux utilisateurs de définir leurs propres types dedonnées au lieu d’utiliser ceux de SQL.Les expressions qui utilisent desdonnéesdetypedéfiniparl’utilisateurdoiventévaluerunélémentdumêmetype.
LesexpressionsdevaleursdeligneUneexpressionvaleurde ligne spécifie,etcen’estpasunesurprise,unevaleur de ligne. Celle-ci peut consister en une ou plusieurs expressionsséparéesparunevirgule.Parexemple:
(‘JosephTykociner’,‘ProfesseurEmérite’,1918)
Ils’agitd’uneligned’unetabledécrivant toutel’histoired’uneuniversité.Ellecontientlenom,lerangetl’annéed’intégrationd’unprofesseur.
LesexpressionsdevaleursdecollectionUneexpressionvaleurdecollectionestévaluéecommeuntableau.
LesexpressionsdevaleursderéférenceUne expression valeur de référence est évaluée comme une valeur quiréférenceunautrecomposantdelabasededonnées,commeunecolonnedetable.
LesprédicatsLes prédicats sont les équivalents SQL des propositions logiques.L’instructionsuivanteestunexempledeproposition:
«L’étudiantestunsenior.»
Dansunetablequicontientdesinformationssurlesétudiants,ledomainedela colonneCLASSE peut êtreSENIOR,JUNIOR,DIPLOME,THESARD
ouNULL. Vous pouvez utiliser le prédicat CLASSE = SENIOR pourisoler toutes les lignes pour lesquelles le prédicat est faux ou toutes leslignes pour lesquelles le prédicat est vrai. Parfois, la valeur du prédicatpouruneligneestindéterminée(NULL).Danscecas,vouspourriezdécidersoitd’éliminerlaligne,soitdelaretenir(aprèstout,l’étudiantpourraitêtreunsenior).Letraitementadaptédépendducasdefigure.
CLASSE=SENIORest un exempledeprédicat de comparaison.SQLdispose de six opérateurs de comparaison. Un prédicat de comparaisonsimplen’utiliseraqu’unseuld’entreeux.LeTableau3.3contientune listedeprédicatsdecomparaisonetdesexemplesdeleurutilisation.
Dansl’exempleprécédent,seuleslesdeuxpremièresentrées(CLASSE=SENIOR et CLASSE <> SENIOR) ont un sens, les autrescomparaisonsn’ayantd’autresignificationquecelled’un trialphabétique,cequin’estpeut-êtrepascequevousattendiez.
TABLEAU3.3Opérateursdecomparaisonetprédicatsdecomparaison.
Opérateur Comparaison Expression
= Egalà CLASSE=SENIOR
<> Différentde CLASSE<>SENIOR
< Inférieurà CLASSE<SENIOR
> Supérieurà CLASSE>SENIOR
<= Inférieurouégalà CLASSE<=SENIOR
>= Supérieurouégalà CLASSE>=SENIOR
ConnecteurslogiquesLes connecteurs logiques vous permettent de construire des prédicatscomplexesàpartird’expressionsplussimples.Supposonsparexemplequevous souhaitiez identifier les enfants prodiges dans une base de donnéesd’étudiants.Deuxpropositionspourraientidentifiercesenfants:
«L’étudiantestunsenior»
«L’âgedel’étudiantestinférieurà14»
Vous pouvez faire appel au connecteur logique AND pour fabriquer unprédicatcomposéquiisolelesenregistrementscorrespondantauxétudiantsrecherchés.Parexemple:
CLASSE=SENIORANDAGE<14
SivousutilisezleconnecteurAND,lesdeuxprédicatsdoiventêtrevalidés(vrais)pourqueleprédicatcomposélesoitaussi.UtilisezleconnecteurORquandvousvoulezqueleprédicatcomposésoitvalidésil’unoul’autredesprédicats qui le compose est validé (ou les deux).NOT est le troisièmeconnecteurlogique.Àproprementparler,NOTnepermetpasdeconnecterdes prédicats, mais il inverse la valeur de l’expression à laquelle vousl’appliquez.Prenonsunexemple:
NOT(CLASSE=SENIOR)
CetteexpressionestvalidéesiCLASSEn’estpaségalàSENIOR.
Lesfonctionsd’ensembleQuelquefois, l’informationquevousvoulezextraired’unetablenedépendpasducontenud’uneligne,maisdeplusieurslignes.SQLdisposedecinqfonctions d’ensemble (ou) pour ce cas. Ces fonctions sontCOUNT, MAX,MIN,SUMetAVG.Chaquefonctionextraitdesdonnéesd’unensembledelignes.
COUNTLafonctionCOUNTretournelenombredelignesdelatablespécifiéequivérifient le critère spécifié. Pour compter le nombre de « seniors »précoces dans la base de données d’étudiants, utilisez par exemplel’instructionsuivante:
SELECTCOUNT(*)
FROMETUDIANT
WHEREGRADE=12ANDAGE<14;
MAXLafonctionMAX renvoie lavaleurmaximalequeprendunecolonnedansunensembledelignes.Supposonsquevoussouhaitieztrouverl’étudiantquia le plus d’ancienneté dans votre école. Vous utiliseriez une instructioncommecelle-ci:
SELECTNOM,PRENOM,AGE
FROMETUDIANT
WHEREAGE=(SELECTMAX(AGE)FROMETUDIANT);
Cette instruction retourne tous les étudiants dont l’âge est égal à l’âgemaximal.C’est-à-direquesil’âgedel’étudiantleplusancienest23,cetteinstruction retournera les noms et les prénoms de tous les étudiants quiont23ans.
Cette requête utilise une sous-requête. La sous-requête SELECT
MAX(AGE)FROMETUDIANTestinclusedanslarequêteprincipale.
MINLa fonctionMIN fonctionne exactement comme la fonction MAX, à ceciprèsqu’ellerecherchelavaleurminimaled’unecolonnedansunensemblede lignes. Pour trouver le plus jeune étudiant, vous pourriez utiliser larequêtesuivante:
SELECTNOM,PRENOM,AGE
FROMETUDIANT
WHEREAGE=(SELECTMIN(AGE)FROMETUDIANT);
Cetterequêteretournetouslesétudiantsdontl’âgeestceluidel’étudiantleplusjeune.
SUM
LafonctionSUMeffectuelasommedesvaleursd’unecolonnedonnée.Lacolonnedoitposséderl’undestypesdedonnéesnumériquesreconnus,etlavaleurde lasommedoitappartenirà laplagedesvaleursautoriséespourcettecolonne.Parexemple,silacolonneestdetypeSMALLINT,lasommenedoitpasdépasser la limitesupérieuredu typededonnéesSMALLINT.Dans labasededonnéesdes clientsquenous avonsutiliséeplushaut, latable FACTURE contient un enregistrement de toutes les ventes. Pourtrouverlavaleurtotaledecelles-ci,utilisezlafonctionSUMdelamanièresuivante:
SELECTSUM(TOTAL_VENTE)FROMFACTURE;
AVGLafonctionAVGretournelamoyennede toutes lesvaleursd’unecolonnedonnée.CommelafonctionSUM,AVGnes’appliquequ’auxcolonnesdontle type de données est numérique. Pour trouver la valeur moyenne desventes,appelezlafonctionAVGdelamanièresuivante:
SELECTAVG(TOTAL_VENTE)FROMFACTURE
Souvenez-vousquelesvaleursnullesn’ontpasdevaleurs.Parconséquent,sideslignesdeTOTAL_VENTEcontiennentdesvaleursnulles(inconnuesounonencoredéfinies),ellesserontpurementetsimplementignoréesdanslecalculdelamoyenne.
Sous-requêtesComme vous avez pu le constater dans la section précédente, les sous-requêtessontdesrequêtesinséréesdansd’autresrequêtes.Partoutoùvouspouvezutiliseruneexpression,vouspouvezaussiutiliserunesous-requête.Lessous-requêtessontparticulièrementutilespourrelierl’informationquecontientunetableàcellequisetrouvedansuneautretable.Vouspouvezeneffet inclureunerequêteportantsurune tabledansunerequêteconcernantune autre table. En imbriquant plusieurs sous-requêtes, il est possibled’accéderaux informationsprovenantdedeuxoudeplusieurs tablespourgénérerlerésultatfinal.
Lelangagedecontrôlededonnées(DCL)
Lelangagedecontrôlededonnées(DCL)disposedequatre instructions :COMMIT,ROLLBACK,GRANTetREVOKE.Cesinstructionsserventtoutesà protéger la base de données de modifications accidentelles ouintentionnellesquipourraientmettreendangersonintégrité.
LestransactionsVotrebasededonnéesestplusvulnérableauxdangerspendantquevousouquiconque la modifiez. Même s’il n’y a qu’un seul utilisateur, toutemodificationpeutserévélerdangereusepourlabasededonnées.Unepannelogicielleoumatériellealorsquel’éditionestencourspeutlaisserlabasededonnéesdansunétatinstableentrecequ’elleétaitavantlamodificationetcequ’elleauraitdûêtreaprèscettemodification.
SQLprotègevotrebasededonnéesenlimitantlesopérationssusceptiblesd’affecterlabasededonnéesdetellesortequecesopérationsnepeuventsedérouler que dans le cadre de transactions. Durant une transaction, SQLenregistrechaqueopérationsurlesdonnéesdansunfichierjournal(oulog).Siunévénementquelconqueinterromptlatransactionavantquel’instructionCOMMITn’ymette un terme, vous pouvez restaurer le système dans sonétat initial en utilisant l’instruction ROLLBACK. ROLLBACK exécute lefichierdelogdanslesensinverse,annulanttouteslesactionsquiyfigurent.Une fois restauré l’état initial de la base de données, vous pouvezrechercherlacauseduproblèmeetprocéderàunenouvelletransaction.
Tant qu’un problème logiciel ou matériel peut survenir, votre base dedonnéesestsusceptibled’êtreendommagée.Pourminimiserlesrisques,lesSGBD effectuent toutes les opérations qui modifient la base de donnéesdanslecontextedetransactionsetvalidentcesopérationslesunesaprèslesautres.Lessystèmesdegestiondebasesdedonnéesmodernesutilisent lelogging en plus des transactions pour garantir qu’un problème logiciel,matérielouopérationnelnecauserapasdedommagesàlabasededonnées.Unefoisquelatransactionaétévalidée,elleestpréservéedetout(saufdescatastrophesmajeures !). Insistonsencore : tantque l’instructionCOMMITn’a pas été exécutée, la machine à remonter le temps permet de revenir
jusqu’au point de départ d’une transaction.Une fois le problème corrigé,l’histoirepeutreprendresonfilnormal.
Sur un système multi-utilisateur, une base de données risque d’êtrecorrompueet/oudeproduiredes résultats erronés sansque survienneunequelconque panne logicielle ou matérielle. Les interactions entre lesdifférentsutilisateursquiaccèdentàlamêmetableaumêmeinstantsonteneffet susceptibles de poser de sérieux problèmes. En limitant lesmodificationsdesortequ’ellesnepuissentseproduirequedanslecadredetransactions,SQLrésoutaussicettedifficulté.
Eneffectuanttouteslesopérationsquipeuventaffecterlabasededonnéesdanslecadredetransactions,vouspouvezisolerlesactionsd’unutilisateurdecellesd’unautreutilisateur.Celaestvitalpourgarantirquelesrésultatsserontcorrects.
Vous vous demandez peut-être comment les interactions entre deuxutilisateurspeuventproduiredesrésultatserronés.SupposonsparexemplequeDidierliseunenregistrementdansunetabled’unebasededonnées.Uninstantplus tard,Davidmodifie lavaleurd’unchampnumériquedanscetenregistrement.Didierécritalorsaumêmeemplacementunedonnéequiestfonctionde cequ’il a luquelques secondesplus tôt.CommeDidiern’estpasaucourantdesmodificationsdeDavid, lavaleurqu’ilsaisitn’estpascorrecte.
UnautreproblèmepeutsurvenirsiDidierécritdansunenregistrementpuisqueDavidlitcedernier.SiDidierannulesatransaction,Davidneserapasinformédecetteopération,etilprocéderaàdesmodificationssurlabased’informationsquinesontplusàjour.
LesutilisateursetlesprivilègesHormis la corruption des données qui résulte de pannes logicielles oumatérielles,ouencored’interactionsmalencontreusesentreutilisateurs,unautredangermenacel’intégritéd’unebasededonnées:lesutilisateurseux-mêmes.Certainespersonnesnedevraientpaspouvoiraccéderdu toutauxdonnées. D’autres devraient ne pouvoir accéder qu’à certaines données,maispasàtoutes.Etd’autresencoredevraientpouvoiraccéderàtoutsansaucune contrainte. Vous avez donc besoin d’un système permettant decataloguer les utilisateurs et d’affecter (ou de refuser) des privilèges auxmembresdesdifférentescatégories.
Le créateur d’un schéma spécifie qui est considéré comme étant sonpropriétaire. En tant que propriétaire du schéma, vous avez le droitd’accorder des privilèges d’accès à vos utilisateurs. Tout privilège quevous n’accordez pas explicitement est considéré comme étant refusé. Lesprivilègessontaussisusceptiblesd’êtreretirésàtoutmoment.Unutilisateurdoit passer par une procédure d’authentification afin de prouver sonidentité. Ce n’est qu’après avoirmontré patte blanche qu’il sera capabled’accéder aux fichiers et aux données pour lesquels il dispose deprivilèges. La procédure exacte dépend de l’implémentation (voire dumatérielsilasécuritéexigeunelectured’empreintesdigitalesoudel’iris).
SQLvouspermetdeprotégerlesobjetssuivants:
» Lestables.
» Lescolonnes.
» Lesvues.
» Lesdomaines.
» Lesjeuxdecaractères.
» Lesséquencesd’interclassement.
» Lestraductions.
Je traite des jeux de caractères, des séquences d’interclassement et destraductionsdansleChapitre5.
SQL supporte plusieurs types de protection : voir, ajouter, modifier,supprimer,référenceretutiliserlesbasesdedonnées.Ilexistedesurcroîtdesprotectionsassociéesàl’exécutionderoutinesexternes.
Vousaccordezunprivilèged’accèsenfaisantappelàl’instructionGRANTet vous le supprimez avec l’instruction REVOKE. En supervisant lefonctionnementdel’instructionSELECT,leDCLcontrôlequialedroitdevoirunobjetdelabasededonnéescommeunetable,unecolonneouencoreune vue. De même, la maîtrise sur l’instruction INSERT permet dedéterminerquipeutajouterdenouvelleslignesàunetable.Demêmeaussi,restreindre l’emploi de l’instruction UPDATE permet de n’autoriser lamodification des lignes des tables qu’aux seuls utilisateurs autorisés. Et
restreindrel’usagedel’instructionDELETEsertàdéfinirquialedroitdesupprimerdeslignesdansdestables.
Siunetabled’unebasededonnéesdéfinitcommecléétrangèreunecolonnequiestcléprimairedansuneautretable,vouspouvezajouterunecontrainteà la première table de sorte qu’elle référence la seconde (les clésétrangèressontdécritesdansleChapitre5).Quandune tableenréférenceainsi une autre, son propriétaire peut être à même de déduire desinformationssurlecontenudelaseconde.Etsivousêteslepropriétairedela seconde table, il n’estpas certainquecetteperspectivevous enchante.L’instruction GRANT REFERENCES de SQL vous donne le pouvoird’empêcher une telle intrusion. La section suivante présente le problèmeposéparune référence inattendueetmontrecomment l’instructionGRANTREFERENCES permet de le résoudre. Grâce à l’instruction GRANTUSAGE,ilestpossibledecontrôlerquialedroitd’utiliseroudevisualiserle contenu d’un domaine, d’un jeu de caractères, d’une séquenced’interclassementoud’unetraduction.
Le Tableau 3.4 contient la liste des instructions que SQL met à votredispositionpouraccorderetretirerdesprivilèges.
TABLEAU3.4Lestypesdeprotection.
Opérationdeprotection Instruction
Permettredevoirunetable GRANTSELECT
Interdiredevoirunetable REVOKESELECT
Permettred’ajouterdes
lignesàunetable
GRANTINSERT
Interdired’ajouterdeslignes
àunetable
REVOKEINSERT
Permettredemodifierdes
donnéesdansdeslignes
d’unetable
GRANTUPDATE
Interdiredemodifierdes
donnéesdansdeslignes
d’unetable
REVOKEUPDATE
Permettredesupprimerdes
lignesdansunetable
GRANTDELETE
Interdiredesupprimerdes
lignesdansunetable
REVOKEDELETE
Permettrederéférencerune
table
GRANTREFERENCES
Interdirederéférencerune
table
REVOKEREFERENCES
Permettred’utiliserun
domaine,unetraductionde
caractèresouunecollation
GRANTUSAGEONDOMAIN,GRANT
USAGEONCHARACTERSET,GRANT
USAGEONTRANSLATION
Interdired’utiliserun
domaine,unetraductionde
caractèresouunecollation
REVOKEUSAGEONDOMAIN,REVOKE
USAGEONCHARACTERSET,REVOKE
USAGEONTRANSLATION
Vouspouvezattribuerdifférentsniveauxd’accèsàdifférentespersonnes,etceenfonctiondeleursbesoins.Voiciquelquesexemples:
GRANTSELECT
ONCLIENT
TORESPONSABLE_VENTES;
permetàunepersonne,enl’occurrenceleresponsabledesventes,devoirlatableCLIENT.
L’exemple suivant autorisequiconquedisposant d’un accès au systèmedevoirlalistedesprixpublics:
GRANTSELECT
ONPRIX_PUBLICS
TOPUBLIC;
Nous voulonsmaintenant permettre au responsable des ventes d’éditer lalistedesprixpublics.Ildoitavoirlapossibilitédemodifierlecontenudelignesdéjàprésentes,maissanspouvoirniensupprimernienajouter:
GRANTUPDATE
ONPRIX_PUBLICS
TORESPONSABLE_VENTES;
Sileresponsabledesventesestautoriséàajouterdenouvelleslignesdanslalistedesprixpublics,nousécrirons:
GRANTINSERT
ONPRIX_PUBLICS
TORESPONSABLE_VENTES;
Grâce à ce dernier exemple, le rôle du responsable des ventes s’accroîtencore,etilpeutmaintenantsupprimerdeslignesdelatable:
GRANTDELETE
ONPRIX_PUBLICS
TORESPONSABLE_VENTES;
Lescontraintesd’intégritéréférentiellepeuventcompromettrevosdonnéesVous pourriez croire que le contrôle des fonctions de visualisation, decréation, de modification et de suppression dans une table suffit à vousprotéger.En fait, unpirate compétentpourrait trèsbienvousdévaliser enutilisantuneautreméthode.
Une base de données relationnelle correctement conçue possède uneintégrité référentielle, cequi signifieque lesdonnéesd’une tabledecettebase sont encohérenceavec lesdonnéesde toutes les autres tables.Pourassurer cette intégrité référentielle, les concepteurs de bases de donnéesappliquentauxtablesdescontraintesqui limitentcequ’ilestpossibled’ysaisir. Si votre base de données est dotée de contraintes d’intégritéréférentielle, unutilisateurpeut avoir lapossibilitéde créerunenouvelletableutilisantcommecléétrangèreunecolonned’unetableconfidentielle.Cette colonne sert alors de lien via lequel quelqu’un peut subtiliser desinformationsconfidentielles.
Précisonscetteidée.Vousêtesuncélèbreanalysteboursier,disonsdeWallStreet.Beaucoupdegenscroientenlapertinencedevosachats,sibienquechaquefoisquevousnégociezdesactionspourlecomptedevosclients,denombreusespersonnessuivent lemouvement,cequi faitmonter lescours.Vous conservez vos analyses dans une base de données qui contient unetablenomméeQUATRE_ETOILES.Toutesvos recommandations lesplusprécieusesysontstockées.Bienentendu,vousrestreignezl’accèsàlatableQUATRE_ETOILESdemanière1)queseulsvosclientspayantspuissenty accéder et 2) qu’ils nepuissent le faire quequandvous les y autorisez(parlebiaisparexempled’unelettred’informationpériodique).
Cependant, vous restez vulnérable si quelqu’un peut créer une nouvelletable qui utilise le nomd’une colonne deQUATRE_ETOILES commecléétrangère,commedansl’exemplesuivant:
CREATETABLEBONNES_ACTIONS(
ACTIONCHARACTER(30)REFERENCESQUATRE_ETOILES
);
Lepiratepeutmaintenantessayerd’insérer lenomdechaqueactioncotéeen Bourse. Les insertions réussies lui indiqueront quelles actions sontstockéesdansvotretableconfidentielle,etilneluifaudrapasbeaucoupdetempspourpillervossiprécieusesinformations.
Vouspouvezvousprotégerde telsassautsen faisant trèsattention lorsquevoussaisissezdesinstructionstellesquecelle-ci:
GRANTREFERENCES(ACTION)
ONQUATRE_ETOILES
TOJESUISUN_HACKER;
Clairement, j’exagère ici. Vous ne donneriez jamais accès à une tablecritiqueàunepersonnequineseraitpasdignedeconfiance,n’est-cepas?Dumoins,sivousavezréalisécequevousfaites.Toutefois,lespiratesnemaîtrisentpasseulementlatechniquedenosjours.Ilssontaussidesexpertsde l’ingénieriesociale, l’art de tromper les gens pour leur faire faire cequ’ils ne feraient pas normalement.Méfiez-vous de ceux quimentionnentquoiquecesoitenlienavecdesinformationsconfidentielles.
Évitezd’accorderdesprivilègesàdespersonnesquipourraientenabuser.Vous n’êtes pas disposé à prêter votre voiture à quelqu’un pour un longvoyage ? Alors ne lui accordez pas de privilège REFERENCE sur unetablequevousjugezimportante.
La liste suivante décrit deux autres bonnes raisons de n’accorder desprivilègesqu’avecparcimonie:
» Sil’autrepersonne(lepirate)spécifieunecontraintesur
BONNES_ACTIONSenutilisantl’optionRESTRICTetque
voustentezensuitedesupprimerunelignedevotretable,
leSGBDvousinformeraquevousnepouvezpaslefairecar
ceseraitviolerl’intégritérelationnelle.
» SivousvoulezutiliserlacommandeDROPpourdétruire
votretable,vousverrezqu’ilvousfaudrad’abordattendre
quel’autrepersonne(toujoursleméchantpirate)ait
supprimésacontrainte(ousatable).
Pourconclure,retenezquepermettreàuneautrepersonnedespécifierdescontraintes d’intégrité sur votre table génère non seulement des failles desécurité,maisaussilametdansunepositionoùellepourraitvousbarrerlechemin…
Déléguerlaresponsabilitédelasécurité
Si vous voulez que votre système reste sécurisé, vous devez sévèrementlimiter l’attribution des privilèges d’accès ainsi que le nombre depersonnesauxquellesvouslesaccordez.Cependant,lesgensquin’arriventpas à travaillerparcequ’ils sontbloquésparde tropgrandes restrictionsrisquent de vous harceler du matin au soir. Pour éviter la dépression,n’hésitez pas à déléguer certaines responsabilités dans la gestion de lasécuritédevotrebasededonnées.Considérezl’exemplesuivant:
GRANTUPDATE
ONPRIX_PUBLICS
TORESPONSABLE_VENTESWITHGRANTOPTION
CetteinstructionressembleauprécédentexempleGRANTUPDATEencequecette instructionpermetau responsabledesventesdemettreà jour laliste des prix. Cependant, elle lui donne aussi le droit de rétrocéder ceprivilègeàn’importequelleautrepersonne.Sivousutilisezcetteformedel’instructionGRANT,vouschoisisseznonseulementdefaireconfianceàlapersonne à laquelle vous accordez le privilège,mais aussi à celles à quicettepersonneletransmettra.
La formeultimede laconfiance,etdonc la formeultimedevulnérabilité,estd’exécuteruneinstructiontellequecelle-ci:
GRANTALLPRIVILEGES
ONQUATRE_ETOILES
TOBENEDICT_ARNOLDWITHGRANTOPTION;
Faitestrèsattentionquandvousutilisezdetellesinstructions(puisquevousdonnezparricochettouslesprivilègesàlaplanèteentière).
IIUtiliserSQLpourcréerdesbasesdedonnées
DANSCETTEPARTIE:
Créerdesstructuressimples.
Établirdesrelationsentrelestables.
L
Chapitre4Créeretmaintenirunesimplestructuredebasededonnées
DANSCECHAPITRE:
» Créer,modifieretsupprimerunetabledebasededonnéesenutilisantunRAD.
» Créer,modifieretsupprimerunetabledebasededonnéesenutilisantSQL.
» MigrervotrebasededonnéesversunautreSGBD.
’informatiqueévoluesiviteque lasuccessiondes«générations»peutparfois paraître confuse. Les langages de haut niveau (ou de troisièmegénération) telsqueFORTRAN,COBOL,Basic,PascaletC furent les
premiers à utiliser les bases de données. Quelque temps plus tard, deslangagesspécifiquementconçuspourlesbasesdedonnéestelsquedBase,ParadoxetR:BASE(troisièmegénérationetdemie?)firentleurapparition.Ladernière étapedecette évolutionest l’émergenced’environnementsdedéveloppement tels qu’Access, Delphi, IntraBuilder et C++ Builder(langages de quatrième génération ou L4G) qui permettent de créer desapplications avec très peu de programmation procédurale, voire aucune.Mais nous n’en sommes déjà plus à ces générations, depuis l’apparitiond’environnements de développement rapides (RAD, pour RapidApplicationDevelopment)etlesenvironnementsintégrésdedéveloppement(IDEpourIntegratedDevelopmentEnvironnments)telsqu’EclipseetVisualStudio.NET,quipeuventêtreutilisésavecdenombreuxlangages(telsqueC,C++,C#,Python,Java,VisualBasicouPHP).Vouspouvez lesutiliserpourassemblerdescomposantsapplicatifsetréaliserainsiuneapplication.
DufaitqueSQLn’estpasunlangagecomplet,iln’appartientpasàunedescatégoriesquejeviensdeprésenter.Ilutilisedesinstructionsàlamanièredes langages de troisième génération, mais il est pour l’essentiel non
procédural,commelesont lesL4G.Maispeu importe laclassificationdeSQL.Vouspouvezl’utiliserenconjonctionavec tous lesprincipauxoutilsdedéveloppementdeslangagesdetroisièmeetquatrièmegénération.Vouspouvez écrire le code SQL vous-même ou le faire générer parl’environnementdedéveloppement.Lecodeproduitestdans lesdeuxcasdupurSQL.
Dans ce chapitre, je vais vous expliquer comment créer, modifier etsupprimerunetableenutilisantunRAD.JevousmontreraiensuitecommentfairelamêmechoseenSQL.
CréerunesimplebasededonnéesenutilisantunoutilRAD
Les gens utilisent des bases de données pour conserver la traced’informations importantes. Parfois l’information qu’ils cherchent àenregistrerestsimple,parfoisellenel’estpas.Unbonsystèmedegestionde bases de données fournit ce dont vous avez besoin dans chaque cas.Quelques-uns s’appuient sur SQL.D’autres, comme les outilsRAD, vousproposent un environnement graphique orienté objet. Quelques SGBDproposentlesdeux.Danslessectionssuivantes,jevousmontreraicommentcréerunebasededonnéesàl’aided’unoutilgraphique.J’utiliseMicrosoftAccess,mais la procédure est lamême avec d’autres environnements dedéveloppementpourWindows.
UnscénarioprobableLa première étape dans la création d’une base de données consiste àdéterminer les informations que vous voulez conserver. Prenons unexemple : supposons que vous veniez de gagner 11 millions d’euros auLoto.Desgensdontvousn’aviezplusentenduparlerdepuisdesannéesetdes amis de trente ans se rappellent à votre bon souvenir. Certains vousproposentd’investirdansdesaffairesquirapporterontàcoupsûr.D’autresreprésententdescausespourlesquellesvousdevriezfairedesdons.Enbongestionnaire,vousavez tôt faitde réaliserquecertainesaffaires semblentmoins intéressantes que d’autres. Et que certaines causes valent moinsqu’on les défende que d’autres. Vous décidez de stocker toutes les
propositions qui vous sont faites dans une base de données afin de lesrecenseretdelesétudieréquitablement.
Vouschoisissezdeconserverlatracedesinformationssuivantes:
» Nom.
» Prénom.
» Adresse.
» Ville.
» Étatouprovince.
» Codepostal.
» Téléphone.
» Relation(votrerelationàcettepersonne).
» Proposition.
» Affaireouœuvre.
Comme vous ne voulez pas vous perdre en subtilités, vous décidez destockertoutescesinformationsdansuneseuletabledelabasededonnées.
CréerunetabledebasededonnéesLorsquevouslancezl’environnementdedéveloppementAccess2013,vousêtesaccueilliparl’écranreprissurlaFigure4.1.Delà,vouspouvezcréerune tabledebasededonnéesdedifférentesmanières. Jevaiscommencerpar lemodeFeuille dedonnées, car elle vousmontre comment créer unebasededonnéesàpartirderien.
FIGURE4.1L’écrand’accueildeMicrosoftAccess.
CréerunetabledebasededonnéesdanslemodeFeuillededonnéesPardéfaut,Access2013s’ouvresurlemodeFeuillededonnées.PourcréerunebasededonnéesAccessdanscettevue,double-cliquezsur lemodèleBase de données duBureau vide.Votre feuille de donnéesAccess attendquevous saisissiezdesdonnéesdansTable1, lapremière tabledevotrebasededonnées,commesurlaFigure4.2.Vouspourrezmodifierlenomdelatablepourluidonnerunnomplussignifiantultérieurement.Accessdonneà votre base de données le nom par défautBasededonnées1 (ouBasededonnées31sivousavezdéjàcréé30basesdedonnéesetquevousnevousêtespasdonnélapeinedelesrenommer).Ilvautmieuxdonnerunnomsignifiantàlabasededonnéespourévitertouteconfusion.
C’estuneméthodequipartderien,maisilexisted’autresmanièresdecréerunetabledansunebasededonnéesAccess.Parlasuite,nousutiliseronslemodeCréation.
CréerunetabledansunebasededonnéesenvueCréation
DanslemodeFeuillededonnées(représentéesurlaFigure4.2),ilesttrèsfaciledecréerunetabledebasededonnées:vousn’avezqu’àcommenceràsaisirlesdonnées.Toutefois,cettemanièredefaireestsujetteauxerreurs,caronoublierapidementdesdétails.IlvautmieuxutiliserlemodeCréationensuivantlesétapessuivantes:
FIGURE4.2LemodeFeuillededonnéesdansl’environnementdedéveloppement
Access.
1. DanslemodeFeuilledecalcul(pardéfaut),cliquezsur
l’ongletAccueildanslerubanetcliquezsurAffichage
endessousdel’icônequisetrouvedansl’angle
supérieurgauchedelafenêtre.SélectionnezMode
créationdanslemenudéroulant.
LorsquevouschoisissezlemodeCréation,uneboîtede
dialogueapparaîtpourvousdemanderlenomdelatable.
2. SaisissezLOTOetcliquezOK.
LemodeCréationapparaît(représentésurlaFigure4.3).
Notezquelafenêtreestdiviséeenzonesfonctionnelles.
Deuxd’entreellessontparticulièrementutilespourcréer
destablesdebasesdedonnées:
• LesoptionsdumodeCréation:Unmenuenhautdela
fenêtredonneaccèsauxoptionsAccueil,Créer,
Donnéesexternes,Outilsdebasededonnéeset
Création.
Lorsquecerubanestaffiché,lesoutilsdisponibles
danslemodeCréationsontreprésentéspardes
icônessetrouvantimmédiatementsouslemenu.Sur
laFigure4.3,lamiseenexerguemontrequeles
icônesCréationetCléprimairesontsélectionnées.
FIGURE4.3L’écrandedémarragedumodeCréation.
• Lepanneaudespropriétésduchamp:Danscette
zonequipermetdedéfinirleschampsdelabasede
données,lecurseurclignotedanslacolonneNomdu
champdelapremièreligne.Accesssuggèrequevous
spécifieziciunecléprimaire,quevouslanommiez
ID,etilluidonneraautomatiquementletypede
donnéesNuméroAuto.
NuméroAutoestuntypededonnéesAccess,etnonuntype
dedonnéesstandardenSQL.Ilincrémenteunentierdans
lechampchaquefoisquevousajoutezunnouvel
enregistrementdanslatable.Cetypededonnéesvous
garantitquelechampquevousutilisezcommecléprimaire
neprendrapasdeuxfoislamêmevaleur,toutecléprimaire
devantêtreunique.
3. DanslazonePropriétésduchamp,modifiezNomdu
champpourlacléprimaireenlepassantdeIDàNUME-
RO_PROPOSITION.
LenomproposédansNomduchamppourlacléprimaire,
ID,n’estpastrèsexplicite.Sivousprenezl’habitudedele
changerenquelquechosedeplussignifiant(et/oude
fournirunedescriptiondanslacolonneDescription),ilsera
plusfaciledegarderunetracedelaraisond’êtredes
champsdansvotrebasededonnées.Ici,lesnomsdes
champssontsuffisammentexplicites.
LaFigure4.4vousmontreàquoiressemblelacréationdela
tabledelabasededonnéesàcetteétape.
4. DanslepanneauPropriétésduchamp,vérifiezles
hypothèsesformuléesautomatiquementparAccess
surlechampNUMERO_PROPOSITION.
LaFigure4.4montrequeceshypothèsessontles
suivantes:
• LatailleduchampestEntierlong.
• Lesnouvellesvaleurssontgénéréespar
incrémentation.
FIGURE4.4Utilisezunnomdechampsignifiantpourdéfinirlacléprimaire.
• L’indexationestactivéeetlesdoublonsnesontpas
autorisés.
• L’alignementdutexteestgénéral.
Commec’estsouventlecas,leshypothèsesformuléespar
Accessconviennentàcequevoussouhaitezfaire.Sice
n’étaitpaslecas,vouspourriezlesmodifierensaisissantde
nouvellesvaleurs.
5. Spécifiezlerestedeschampsquevoussouhaitezvoir
danslatable.
LaFigure4.5vousmontrelemodeCréationunefoisque
vousavezsaisilechampPrénom.
FIGURE4.5LafenêtredecréationdelatableunefoisquevousavezdéfiniPrénom.
LetypededonnéespourPRENOMestTextecourtplutôtqueNuméroAuto,sibienquelespropriétésduchampsontdifférentes.Enl’occurrence,AccessadonnéàPRENOMlatailledechamppardéfaut,c’est-à-dire255caractères.Jeneconnaispasgrandmondedontleprénomsoitaussilong.Accessestassezfutépourn’allouerdemémoirequ’enfonctiondecequiestsaisi.Iln’allouepas255octetsàl’aveugle.Toutefois,d’autresenvironnementsde
développementpeuventnepasenêtrecapables.J’aimepréciserunevaleurraisonnablecommetailledechamp.Celam’évitedesproblèmesquandjepassed’unenvironnementdedéveloppementàunautre.
L’hypothèsepardéfautd’AccessestquePrénom
n’estpasunchampobligatoire.Vouspourriezsaisir
unenregistrementdanslatableLOTOetlaisserce
champvide,cequipermettraitdetenircomptedes
gensquin’ontqu’unnom,commeCherouBono.
ANTICIPEZLORSQUEVOUSCONCEVEZVOTRETABLE
Dans certains environnements de développement (différents
d’Access), réduire la taille du champ Prénom à 15 octets permet
d’économiser240octetspourchaqueenregistrementdans labasede
données si vous utilisez des caractères ASCII (UTF-8), 480 octets si
vousutilisezdescaractèresUTF-16,ou960octetssivousutilisezdes
caractères UTF-32. L’économie devient vite considérable. Tant que
vous y êtes, jetez un œil sur les autres hypothèses par défaut
formuléessur lesautrespropriétésduchamp,etessayezd’anticiper
comment vous voudrez les utiliser tandis que la base de données
s’enrichira. Il fautsepréoccuperdecertainestoutdesuitepourplus
d’efficacité (la taille du champ est un bon exemple) ; d’autres ne
s’appliquerontquedansdescasobscurs.
Vous aurez sans doute remarqué qu’une autre propriété de champ
revient souvent : la propriété Indexé. Si vous n’envisagez pas de
récupérer lavaleurduchamp,negaspillezpaslapuissancedevotre
ordinateurpourl’indexer.Toutefois,notezquedansunegrandetable
comportant de nombreuses lignes, vous pouvez accélérer
considérablement la récupération en indexant le champ que vous
utilisezpouridentifierl’enregistrementquevoussouhaitezrécupérer.
Enmatièredeconceptiondetablesdebasesdedonnées,lediablese
logedanslesdétails.
6. Passezlatailleduchampà15.
Poursavoirpourquoic’estunebonneidée,reportez-vousà
l’encadré«Anticipezlorsquevousconcevezvotretable».
7. Pourvousassurerquevouspouvezrécupérerun
enregistrementrapidementdanslatableLOTOàpartir
dePrénom,passezlapropriétéIndexédecechampà
Oui,commesurlaFigure4.6.
FIGURE4.6LafenêtredecréationunefoisquePrénomaétédéfini.
LaFiguremontrequelquesmodificationsquej’aiapportées
danslepanneauPropriétésduchamp:
• J’airéduitlataillemaximaleduchampde255à20.
• J’aipasséNullinterditàOui,Chaînevideautoriséeà
NonetIndexéàOui-Avecdoublons.Jeveuxque
chaquepropositioncomprennelenomdefamillede
lapersonnequienestl’auteur.Unnomdetaillenulle
n’estpasautorisé,etlechampNomdoitêtreindexé.
• J’aiautorisélesdoublons;deuxouplusieurs
personnespeuventparfaitementavoirlemêmenom
defamille.C’estpratiquementcertaindanslecasde
latableLOTO;j’attendsdespropositionsdemes
troisfrères,ainsiquedemesenfantsetdemafille
quin’estpasencoremariée,sansmentionnermes
cousins.
• L’optionOui-Sansdoublons,quejen’aipaschoisie,
seraitadaptéepourunchampquiseraitlaclé
primairedelatable.Eneffet,lacléprimaired’un
enregistrementdevraittoujoursêtreunique.
8. Saisissezlerestedeschamps,enmodifiantla
propriétéTailleduchampcommenécessaireselonle
cas.
LaFigure4.7vousprésentelerésultat.
FIGURE4.7Lafenêtredecréationdelatableunefoisquetousleschampsontétédéfinis.
CommevouspouvezleconstatersurlaFigure4.7,lechamp
pourlesentreprisesetlesassociations(AFFAIRE_OEUVRE)
n’estpasindexé.Iln’estpasutiled’indexerunchampquin’a
quedeuxentréespossibles;l’indexationneviendraitpas
réduirelasélectiondansuneproportiontellequ’elleen
vaudraitlapeine.
Accessutiliseletermedechampplutôtqueceluid’attribut
oudecolonne.Leprogrammen’étaitpasinitialement
relationnel;ilutilisaituneterminologieàbasedefichier,
champetenregistrement,communeauxsystèmesàbasede
fichiersàplat.
9. Enregistrezvotretableencliquantsurl’icônefigurant
unedisquettedansl’anglesupérieurgauchedela
fenêtre.
Ilestbond’anticiperlorsquevousdéveloppezunebasede
données.Parexemple,c’estunebonneidéeque
d’enregistrerfréquemmentvotretravail,cliquezsimplement
surl’icônefigurantunedisquettedetempsentemps.Dela
sorte,vousvousépargnerezdereprendrevotretravails’il
survientunecoupuredecourantouunévènementimprévu.
Aussi,mêmesivouspouvezparfaitementdonnerlemême
nomàlabasededonnéesetàl’unedesestables,vous
risquezd’induireenconfusionlesadministrateursetles
utilisateursparlasuite.Ilvautdoncmieuxsefaireunerègle
d’utiliserdesnomsdifférents.
Unefoisquevousaurezenregistrévotre table,vousdécouvrirezquevousdevrezmodifierunpeuvotrecréation,commejel’expliquedanslasectionsuivante«Modifierlastructuredevotretable».
ModifierlastructuredevotretableBiensouvent,lesbasesdedonnéesquevousconceveznetournentpasronddès la première fois. Si vous travaillez pour le compte d’un client, vouspouvez être quasiment certain que ce dernier va revenir à la charge pourvousdemanderdemodifierlabasededonnées,desortequ’elleconservelatracedetelleoutelleinformationsupplémentaire.
Sivousélaborezlabasededonnéespourvotreproprecompte,vousvousheurterez probablement aux limitations de votre structure, car il estimpossiblede toutprévoir lorsde laconception.Parexemple,vousallezpeut-êtrerecevoirdespropositionsdepuisdiversescontréesetdoncdevoirajouterunecolonnePAYS.Oualorsvousdéciderezdeconserverl’adressede messagerie de vos contacts, et vous devrez insérer une colonneCOURRIEL.Dans tous lescas, ilvousfaudrarevenirsur lastructurequevousavezcréée.Danscettesection,jevaisutiliserAccessafindemodifierlatablequejeviensdecréer.NotezquelesautresoutilsRADdisposentdefonctionnalitéssemblables.
S’ildevientnécessairequevousmettiezàjourlestablesdevotrebasededonnées, prenez un instant pour passer en revue tous les champs qu’elles
utilisent. Par exemple, vous pourriez en venir à ajouter un second champADRESSEpour les personnes dont l’adresse est complexe et un champPAYSpourtenircomptedespropositionsémanantd’autrespays.
Quoiqu’il soit plutôt facile de mettre à jour les tables d’une base dedonnées, vous devriez éviter de le faire autant que possible. Touteapplication qui dépend de la précédente structure de la base de donnéesrisquedenepluspouvoirfonctionneretdevraêtremodifiée.Sivousavezbeaucoupd’applicationsdecetype,latâcherisqued’êtretrèspénalisante.Essayezd’anticiperlesévolutionsnécessaires.Ilvautmieuxpasserunpeuplusdetempssurlaconceptiondelabasededonnéesqued’avoiràmettreà jour des applications écrites il y a des années. En effet, vous risquezd’avoiroubliécommentellesfonctionnent,etdenepaspouvoirlesmettreàjour.
Pour insérer de nouvelles lignes et tenir compte d’évolutions, ouvrez latableetsuivezcesétapes:
1. Danslafenêtredecréationdelatable,cliquezdu
boutondroitsurlepetitcarrécolorésurlagauchedu
champVILLEpoursélectionnerlaligne,et
sélectionnezInsérerunelignedanslemenuqui
apparaît.
Uneligneviergeapparaîtau-dessusdel’emplacementdu
curseur,quidécaleleslignesexistantes,commesurla
Figure4.8.
2. Saisissezleschampsquevoussouhaitezajouterà
votretable.
J’aiajoutélechampADRESSE2au-dessusduchampVILLE,
etunchampPAYSau-dessusduchampTELEPHONE.
3. Unefoisquevousavezterminévosmodifications,
enregistrezlatableavantdelafermer.
LerésultatdoitressembleràlaFigure4.9.
CréerunindexComme le nombre de propositions que vous recevez peut facilement secompterencentaines,vousaurezbesoind’unoutilvouspermettantd’isolerrapidementlesenregistrementsquivousintéressentenfonctiondedifférentscritères.Supposonspar exemplequevous souhaitiez regarder uniquementles propositions de toutes les personnes qui se prétendent votre frère.Enpartantdel’idéequ’aucundevosfrèresn’achangésonnompourdesmotifsprofessionnels ou futiles, il est facile de sérier les propositionscorrespondantes en vous basant sur la valeur du champ Nom, comme lemontrelarequêteSQLadhocsuivante:
SELECT*FROMPOUVOIR
WHERENom=‘Marx’;
FIGURE4.8Lafenêtredecréationdelatableaprèsavoirrajoutéunemplacement
pourunesecondeligned’adresse.
FIGURE4.9Votretableréviséedevraitressembleràceci.
Cependant, cette stratégie ne peut pas s’appliquer aux propositions quiémanentdevosbeaux-frèresoudevosbelles-sœurs.Ilestpossibledeseconcentrersurcespropositionsenétudiantlavaleurd’unautrechamp:
SELECT*FROMPOUVOIR
WHERERelation=‘beau-frère’
OR
Relation=‘belle-soeur’;
Toutescesrequêtesfonctionnentparfaitement,maisellesrisquentdenepass’exécuter rapidement si POUVOIR contient beaucoup de données (desdizaines de milliers d’enregistrements). En effet, SQL passe la table enrevueligneparligne,àlarecherchedesentréesquipourraientsatisfairelaclause WHERE. Vous pouvez considérablement accélérer les choses enassociant un index à la table POUVOIR (un index est une table depointeurs ;chaquelignedansl’indexpointeversunelignecorrespondantedelatable).
Vouspouvezdéfinirunindexpropreàchacunedesmanièresparlesquellesvous comptez accéder à vos données. Si vous ajoutez, modifiez ousupprimezdeslignesdanslatable,vousn’aurezplusàlatrierdenouveau:ilvoussuffirad’actualiserl’index.Etcettemiseàjours’effectuebeaucoupplus rapidementque le trid’une table.Une foisquevousdisposerezd’unindexcorrespondantautriquevoussouhaitez,vouspourrezl’utiliserpouraccéderauxlignesdelatablepresqueinstantanément.
CommeNUMERO_PROPOSITIONest unique et court, utiliser ce champestlemoyenleplusrapidepouraccéderàunenregistrementdonné.C’estdoncuncandidatidéalpourdevenircléprimaire.Pourlamêmeraison,lacléprimairedechaquetableetdetouteslestablesdevraittoujoursêtreindexée. Voilà qui tombe d’ailleurs bien, car Access indexeautomatiquement les clés primaires ! Cependant, vous devez connaître lavaleurNUMERO_PROPOSITIONdel’enregistrementquevouscherchezpour pouvoir accéder à ces données. C’est pourquoi vous pourriez créerdes index basés sur d’autres champs tels queNOM,CODEPOSTAL ouRELATION.Prenonsunexempleconcret.Danslecasd’unetableindexéesurlechampNom,dèsqu’unerecherchetrouveunelignecontenantMarx,elleadumêmecoupdétectétouslesautresenregistrementsayantlamêmevaleur dans la colonne Nom. Vous pouvez donc retrouver Chico,Groucho,HarpoetZeppopratiquementaussivitequeChicoseul.
La gestion d’un index provoque une charge de travail supplémentaire, etdonc ralentit un peu votre système. Cependant, il permet d’accéderbeaucoupplus rapidementauxdonnées.Vousdevezdoncvousefforcerdetrouverunboncompromisentrecesdeuxpôlescontradictoires.
Voici quelques conseils pour vous aider à choisir les bons champs pourindexervotretable:
» Indexezleschampsquevousutilisezleplussouvent.De
cettemanière,ilserapossibled’accéderrapidementaux
donnéessansquelesurcroîtdetravailimposéausystème
nepénaliseinconsidérémentvosrecherches.
» Neperdezpasvotretempsàcréerdesindexpourdes
champsquinevousserventjamaisdansvoscritères.Ce
seraitungaspillageinutiledetempsetd’espace.
» Créerunindexpourunchampdontlavaleurnepermet
pasd’identifierformellementunesériecohérente
d’enregistrementsn’agénéralementpasdesens.Par
exemple,indexerlechampAFFAIRE_OEUVREneferaitque
diviservotretableendeuxcatégories.Cen’estdoncpasun
candidatintéressant.
L’efficacité d’un index varie d’une implémentation à une autre. Si vousfaites migrer une base de données d’une plate-forme à une autre, il estpossible que les index qui donnaient de bons résultats sur le premiersystèmene fonctionnentplusaussibien sur le second.En fait, ilspeuventmême pénaliser vos performances. Vous devez optimiser la gestion desindexen fonctionde chaqueSGBDetde chaque configurationmatérielle.Essayez différents schémas d’indexation pour juger de celui qui vousprocure lesmeilleures performances d’ensemble.Optimisez vos index demanièreà limiteraumaximumleur impactnégatif sur les rechercheset lamiseàjourdesdonnées.
PourindexerlatablePOUVOIR,sélectionnezsimplementOuipourIndexédanslepanneauPropriétésduchampdanslafenêtredecréationdelatable.
Accesscréeautomatiquementun indexpourCodePostal,carcechampest souvent utilisé pour récupérer des informations. Access indexe aussiautomatiquementlacléprimaire.
Vouspouvezvoir queCodePostaln’est pas une clé primaire et n’estpas nécessairement unique. C’est exactement l’inverse pourNUMERO_PROPOSITION. Ajoutez des index supplémentaires pourNomet Relation, car ces champs serviront probablement de critères lors derecherches.
Une fois que vous avez créé tous vos index, sauvegardez la nouvellestructuredelatableavantdelafermer.
SivousutilisezunautreRADqueMicrosoftAccess, ladémarchedécritedans cette section ne s’applique pas à votre situation. Cependant, leprocessusgénéraldevraitêtrelemême.
SupprimerunetableAucoursdelaconstructiond’unetabletellequePOUVOIR,ilsepeutquevous passiez par quelques versions intermédiaires qui ne correspondentfinalement pas à vos souhaits. La présence de ces tables inachevées peutinduire vos futurs utilisateurs en erreur. Vous feriez donc mieux de lessupprimer tant que vous savez à quoi elles correspondent. Pour ce faire,cliquezduboutondroit sur la tablequevous souhaitez supprimerdans lalisteTouteslestablessurlecôtégauchedelafenêtre.Unmenuapparaît,etl’une des options qu’il propose est Supprimer. Lorsque vous cliquez surSupprimer,commelemontrelaFigure4.10,latableestretiréedelabasededonnées.
FIGURE4.10SélectionnezSupprimerpoursupprimerunetable.
Si Access supprime une table, il supprimera aussi toutes celles qui endépendent,ainsiquetoussesindex.
CréerunetableavecleDDLdeSQLTouteslesfonctionsdedéfinitiondelabasededonnéesdontvousdisposezviaunoutilRADtelqu’AccesspeuventaussiêtreeffectuéesenSQL.Plutôtque de cliquer dans des menus avec la souris, vous devrez saisir descommandes au clavier. Certaines personnes, qui préfèrent manipuler desobjets visuels, pensent que les outilsRAD sont plus faciles d’utilisation.D’autres, plus orientées vers la formulation de leur besoin par desséquences d’instructions logiques, trouvent que les instructions SQL sontplussimples.
Certains concepts se prêtentmieux à une représentation graphique, tandisqued’autressegèrentplusdirectementsousSQL.Ilestdoncutiledebienmaîtriserl’uneetl’autredecesméthodes.
Dans lessectionssuivantes, j’utiliseSQLpoureffectuer lesopérationsdecréation,modificationetsuppressiondetablequenousvenonsd’effectueràl’aideduRAD.
UtiliserSQLavecMicrosoftAccessAccess est par essence un outil de développement rapide (RAD) qui nenécessite pas de programmation. Il est évidemment possible d’écrire desinstructions SQL sous Access, mais vous devrez pour cela passer par laportedederrière…Voicicommentouvrirunéditeur(basiqueaudemeurant)danslequelvoussaisirezvotrecodeSQL:
1. Ouvrezvotrebasededonnéesetcliquezsurl’onglet
Créerpourafficherlerubanenhautdel’écran.
2. CliquezsurCréationderequêtedanslasection
Requêtes.
LaboîtededialogueAfficherlatableapparaît.
3. SélectionnezlatableLOTO.Cliquezsurlebouton
Ajouter,puissurFermerpourfermerlaboîtede
dialogue.
Vousdevriezvoirs’affichercequiestreprésentésurla
Figure4.11.
UneimagedelatableLOTOetdesesattributsapparaît
danslapartiesupérieuredelazonedetravail,etunegrille
Requêteparexempleapparaîtdessous.Accessattendque
voussaisissiezunerequêteenutilisantcettegrille(vous
pourriezlefaire,c’estsûr,maiscelanevousapprendraitpas
àutiliserSQLdansl’environnementd’Access).
4. Cliquezsurl’ongletAccueilpuissurl’icôneAffichage
dansl’anglegaucheduruban
Unmenuapparaît,quicontientlesdifférentsmodes
auxquelsvouspouvezaccéder,commesurlaFigure4.12.
L’undecesmodesestlavueSQL.
FIGURE4.11L’écranRequêteunefoislatableLOTOsélectionnée.
FIGURE4.12LesmodesdelabasededonnéesdisponiblesenmodeRequête.
5. CliquezsurModeSQLpourafficherl’ongletdela
requêteenSQL.
CommevouslevoyezsurlaFigure4.13,l’ongletdela
requêteenSQLfaitl’hypothèse(trèsrationnelle)quevous
souhaitezrécupérerdesinformationsdelatableLOTO,si
bienqu’ilaécritlapremièrepartiedelarequêtepourvous.
Ilnesaitpasexactementcequevoussouhaitezrécupérer,
sibienqu’iln’affichequecedontilestcertain.
Voicicequ’ilaécritpourvous:
FIGURE4.13LavueSQLdel’ongletObjet.
SELECT
FROMPOUVOIR;
6. Rajoutezunastérisque(*)àlafindelapremièreligne
etajoutezuneclauseWHEREaprèslaligneFROM.
Sivousavezdéjàsaisiquelquesdonnéesdanslatable
LOTO,vouspourriezlesrécupérerdecettemanière:
SELECT*
FROMLOTO
WHEREPrenom=‘Max’;
N’oubliezpaslepoint-virgule(;)quiterminelacommande
SQL.VousdevezlereporterdesapositionaprèsLOTOàla
findelalignesuivante.
7. Lorsquevousavezterminé,cliquezsurl’icônefigurant
unedisquette.
Accessvousdemandededonnerunnomàvotrenouvelle
requête.
8. AttribuezunnomàvotreinstructionetcliquezOK.
Votrerequêteestsauvegardéeetpourraêtreexécutéeàtoutmoment.
CréerunetablePourcréerunetabledebasededonnéesenSQL(dumoinsavecunSGBDqui l’implantepleinement), ilvoussuffitdesaisir lesmêmes informationsquecellesquevousavezspécifiéesenutilisantl’outilRAD.Ladifférenceestque l’outilRADvousaideenaffichantuneboîtededialoguedu styleCréationdetableetvousinterditd’entrerdesnomsdechamps,destypesetdeslongueursquinesontpasvalides.
SQLnevousaidepasbeaucoup.Vousdevezsavoiràl’avanceexactementce que vous faites, car il vous faudra saisir la totalité de l’instructionCREATETABLEavantqueSQLnecommenceàlacontrôlerpourvérifiersiellecontientounondeserreurs.Jusque-là,vousêtestotalementseul.
L’instructionquicréeunetabledesuividespropositionsidentiqueàcellequenousavonsdéfinieprécédemmentadoptelasyntaxesuivante:
CREATETABLELOTO_SQL(
NUMERO_PROPOSITIONINTEGERPRIMARYKEY,
PRENOMCHAR(15),
NOMCHAR(20),
ADRESSECHAR(30),
VILLECHAR(25),
ETAT_PROVINCECHAR(2),
CODE_POSTALCHAR(10),
PAYSCHAR(30),
TELEPHONECHAR(14),
RELATIONCHAR(30),
PROPOSITIONCHAR(50),
AFFAIRE_OEUVRECHAR(1));
Comme vous pouvez le constater, l’information que contient l’instructionSQLestessentiellementlamêmequecellequevousavezsaisievial’outilRAD.Cependant,SQLprésente l’avantaged’êtreunlangageuniversel.Lamême syntaxe fonctionne sur tous les systèmes de gestion de bases dedonnées.
DansAccess2013,lacréationd’objetsdansunebasededonnéestelsquelestablesestunpeupluscomplexe.VousnepouvezpassimplementsaisirlacommandeCREATE(commevousvenezdelevoir)dansl’ongletdelarequêteenSQL.C’estparcequecetongletnesertqued’outilderequête;vous devez procéder à quelques actions supplémentaires pour informerAccessquevoussouhaitezsaisirunerequêtededéfinitiondedonnéesplutôtqu’unerequêtenormalequinefaitquedemanderdesinformationsfigurantdans la base de données.Une autre complication : comme la création detable pourrait compromettre la sécurité de la base de données, elle estinterditepardéfaut.VousdevezindiqueràAccessqu’ils’agitd’unebasededonnées de confiance avant qu’il accepte la requête de définition dedonnées.
1. Cliquezsurl’ongletCréerdanslerubanpourafficher
lesicônesrelativesàlacréation.
2. CliquezsurlemodeCréationdanslasectionRequêtes.
CelaaffichelaboîtededialogueAfficherlatable,qui
contientpourl’heureplusieurstablessystèmesenplusde
LOTO.
3. SélectionnezLOTOetcliquezsurleboutonAjouter.
Commevousl’avezvudansl’exempleprécédent,uneimage
delatableLOTOetdesesattributsapparaîtdanslamoitié
supérieuredel’écran.
4. CliquezsurleboutonClonedanslaboîtededialogue
Afficherlatable.
5. Cliquezsurl’ongletAccueil,puissurl’icôneAffichageà
gaucheduruban,etsélectionnezModeSQLdansla
listedéroulantequiapparaît.
Commedansl’exempleprécédent,Accessvousa«aidé»en
rajoutantSELECTFROMLOTOdansl’éditeurSQL.Cette
fois,vousn’envoulezpas.
6. SupprimezSELECTFROMLOTOetsaisissezàlaplacela
requêtededéfinitiondedonnéesprésentéeplustôt,
commesuit:
CREATETABLELOTO_SQL(
NUMERO_PROPOSITIONINTEGERPRIMARYKEY,
PRENOMCHAR(15),
NOMCHAR(20),
ADRESSECHAR(30),
VILLECHAR(25),
ETAT_PROVINCECHAR(2),
CODE_POSTALCHAR(10),
PAYSCHAR(30),
TELEPHONECHAR(14),
RELATIONCHAR(30),
PROPOSITIONCHAR(50),
AFFAIRE_OEUVRECHAR(1));
Àcetinstant,votreécrandevraitressembleràlaFigure4.14.
FIGURE4.14Larequêtededéfinitiondedonnéespourcréerunetable.
7. Aprèsavoircliquésurl’ongletCréerdansleruban,
cliquezsurlepointd’exclamationdel’icôneExécuter.
Cefaisant,vousexécutezlarequête,cequicréelatable
LOTO_SQL(commesurlaFigure4.15).
VousdevriezvoirapparaîtreLOTO_SQLsousTouslesobjets
Accessdanslacolonnefigurantsurlecôtégauchedela
page.Danscecas,vousavezdelachance.Oualors,vousne
voyezpaslatabledanslalisteTouslesobjetsAccess.Si
c’estlecas,continuezdelire.
FIGURE4.15CréationdelatableLOTO_SQL.
Access2013faitdegroseffortspourvousprotégercontre
deshackersmalintentionnésetdesutilisateurs
imprudents.Commeexécuterunerequêtededéfinitionde
donnéespeutconstituerundangerpourlabasede
données,Accessinterditpardéfautl’exécutiond’unetelle
requête.Sivousrencontrezcetobstacle,LOTO_SQL
n’apparaîtrapasdanslacolonnesurlagauchedelafenêtre
carlarequêten’aurapasétéexécutée.
Àlaplace,vousverrezapparaîtrecemessagedanslabarre
demessagesquisetrouvesousleruban:
AlerteSécurité:Ducontenudanslabasede
donnéesa
étédésactivé.
Sivousvoyezcemessage,suivezcesétapes:
8. Cliquezsurl’ongletFicher,etdanslemenuquiFigure
surlecôtégauchedel’écran,sélectionnezOptions.
LaboîtededialogueOptionsapparaît.
9. SélectionnezCentredegestiondelaconfidentialité
danslabasededonnéesOptionsAccess.
10.CliquezsurleboutonParamètresducentredegestion
delaconfidentialitélorsqu’ilapparaît.
11.SélectionnezBarredemessagesdanslemenusurla
gauche,puisspécifiezAfficherlabarredemessagesen
cliquantsonboutons’iln’estpasdéjàsélectionné.
12.Cliquezpourrevenirenarrière,làoùvousaveztenté
d’exécuterlarequêtededéfinitiondedonnéesquicrée
latableLOTO_SQL.
13.Exécutezlarequête.
Tousleseffortsquevousconsacrezàl’apprentissagedeSQLserontpayantsà long terme, car SQL est parti pour durer. Le temps passé à devenir unexpertd’unoutilRADestbeaucoupmoinsrentable.Aussisophistiquéquesoit un outil RAD, vous pouvez être certain qu’il sera dépassé par unenouvelletechnologiedanslescinqannéesàvenir.Sivouspensezpouvoiramortir le coût de votre formation dans ce délai, parfait ! Formez-vous.Sinon,ilseraitsagedevousenteniràSQL.Etlamêmeremarquevautpourl’ensembledevotreenvironnementdetravail.
CréerunindexLes index sont très importants dans les bases de données. Ils servent depointeursdansdestablesquicontiennentdesdonnéesintéressantes.Sivousutilisez un index, vous pouvez accéder directement à un enregistrementparticulier sans avoir à balayer séquentiellement la table, enregistrement
parenregistrement,àlarecherchedeceluiquevouscherchez.Sansindex,ilvous faudrait peut-être attendre des années et non des secondes pourextraireuneinformationd’unetrèsgrossetable.Desannées,c’estpeut-êtrebeaucoup.Maisuntempssuffisantpourquevousfinissiezparvouslasseretabandonnerlarecherche,celac’estcertain.
D’unemanièresurprenante,lestandardSQLneproposeaucuneinstructionpourcréerunindex.LeséditeursdeSGBDdoiventdoncécrireeux-mêmescette fonctionnalité. Et comme les implémentations ne sont passtandardisées, elles diffèrent les unes des autres. La plupart des éditeursproposent lacréationd’un indexsous la formed’une instructionCREATEINDEX.
Mêmesideuxéditeursutilisent lesmêmesmots,celanesignifiepaspourautantquecesdeuxcommandesagissentdelamêmemanière.Vousdevrezprobablementspécifierdesclausesspécifiquesàl’implémentation.ÉtudiezdoncattentivementladocumentationdevotreSGBDpourélucidercepoint.
Modifierlastructured’unetableVous pouvez utiliser l’instruction ALTER TABLE pour modifier lastructure d’une table qui existe déjà. Contrairement à l’outil RAD quiaffichelastructuredecettetable,SQLvousobligeàlaconnaîtreàl’avancepour la modifier. C’est évidemment moins commode. Par contre,l’utilisationdeSQLestgénéralement laméthodelamieuxadaptéesivousvoulez inclure les instructions qui modifient la table dans un programmed’application.
Pour ajouter un second champ adresse à la table LOTO_SQL, utilisezl’instructionDDLsuivante:
ALTERTABLELOTO_SQL
ADDCOLUMNADDRESS_2CHAR(30);
Vousn’avezpasbesoind’êtreuntechnogourouduSQLpourcomprendrecequ’elleveutdire.Cette instructionmodifieune table appeléeLOTO_SQLenyajoutantunecolonne.Lacolonne s’appelleADRESSE_2,elleestdetypeCHAR(c’estdoncunechaîne)etsalongueurestde30caractères.Cetexemplevousmontrequ’ilesttrèsfaciledemodifierunetableàl’aidedecommandesDDL.
Le standard SQL fournit cette instruction pour ajouter une colonne. Ilpropose symétriquement une instruction vous permettant d’en supprimerune:
ALTERTABLELOTO_SQL
DROPCOLUMNADDRESS_2;
SupprimerunetableIlesttrèsfaciledesupprimerdestablesdontvousn’avezplusbesoinetquiencombrentvotredisquedur:
DROPTABLELOTO_SQL;
Comment celapourrait-il être plus simple ?Si vous supprimezune table,vous détruisez aussi toutes ses données et sesmétadonnées. Il n’en resterien.Celafonctionnebien,saufsiuneautretabledelabasededonnéesfaitréférence à celle que vous essayez de supprimer. Cela s’appelle unecontrainte d’intégrité référentielle. Dans ce cas, SQL vous produira unmessageplutôtquedesupprimerlatable.
SupprimerunindexSivoussupprimezune tableenutilisant l’instructionDROPTABLE,voussupprimezaussilesindexquiysontassociés.Cependant,ilpeutarriverquevous souhaitiez conserver une table mais supprimer un de ses index. Lestandard SQL ne définit pas d’instruction du genre DROP INDEX. Parcontre, vous la trouverez dans la plupart des implémentations. Cettecommande se révèle fort utile quand votre système ralentit, que lesutilisateurscommencentàréclamerdenouveauxordinateurspluspuissants,etquevousdécouvrezquevostablesnesontpasindexéesdelameilleuremanière.
DelaportabilitéToute implémentation de SQL que vous pourrez utiliser disposera trèscertainement d’extensions qui assurent des fonctionnalités qui ne sont pas
mentionnéesdans le standardSQL.Certainesdeces fonctionnalités ferontprobablement leur apparition dans la prochaine version du standard.D’autres sont totalement spécifiques à certaines implémentations et leresterontvraisemblablement.
Cesextensionsfacilitentlacréationd’applications,sibienqu’ilesttentantde les utiliser. Mais n’oubliez pas qu’y recourir présente aussi desinconvénients. Si vous voulez un jour migrer votre application vers uneautreimplémentation,vousdevrezréécrirelessectionsdevotrecodedanslesquelles vous faites référence aux extensions que la nouvelleimplémentation ne reconnaît pas. Pensez-y avant de faire appel auxextensions inclusesdansvotreSGBDactuel.Si elles vous font gagnerdutemps à court terme, elles peuvent aussi vous en faire perdre à plus longterme.
Plusvousenapprendrezsurlesparticularitésdevotresystème,mieuxvousserezàmêmedeprendrelesbonnesdécisions.Parexemple,pouraboutiràlaconclusionqu’ilexisteuneautresolutionàunproblèmexquedepasserpardesextensionsdevotreSGBD.
D
Chapitre5Créerunebasededonnéesrelationnellemultitable
DANSCECHAPITRE:
» Déciderdecequ’ilfautincluredansunebasededonnées.
» Déterminerlesrelationsentrelesdonnées.
» Lierdestablesàl’aidedeclés.
» Préserverl’intégritédesdonnéesdèslaconception.
» Normaliserunebasededonnées.
ans ce chapitre, je vous présente un exemple de base de données quicomporte plusieurs tables. La première étape de la conception d’unetellebaseconsisteàdéciderdecequ’ilfautyinclureetdecequ’ilfaut
en exclure. Les étapes suivantes visent à établir des relations entre lesdonnéesetàconfigurer les tablesenconséquence. Jevousexpliqueaussicomment utiliser les clés, qui permettent d’accéder rapidement à desenregistrementsspécifiquesainsiqu’àdesindex.
Unebasenedoitpassimplementcontenirvosdonnées.Elledoitaussi lesprotéger contre toute forme de corruption. Dans la dernière partie de cechapitre,jevousexpliqueraicommentpréserverl’intégritédevosdonnées.La normalisation étant une des principales méthodes que vous pouvezutiliseràcettefin, jevousprésenterai lesdiversesformesnormaleset lestypesdeproblèmesqu’ellespeuventpermettrederésoudre.
Concevoirlabasededonnées
Suivezlesétapessuivantespourconcevoirlabase(jereviendraiendétailsurchacunedesétapesaprèslesavoirtoutesénoncées):
1. Identifiezlesobjetsquevoussouhaitezstockerdans
votrebasededonnées.
2. Déterminezparmicesobjetsceuxquidevraientêtre
destablesetceuxquidevraientêtredescolonnesdans
cestables.
3. Définissezlestablesconformémentàlamanièredont
vousavezbesoind’organiserlesobjets.
Vouspourriezéventuellementassigneràuneouplusieurs
colonneslerôledeclé.Lescléspermettentdelocaliser
rapidementdansunetablelalignequivousintéresse.
Lessectionssuivantesreviennentdansledétailsurchacunedecesétapes.
Étape1:IdentifierlesobjetsLa première étape de la conception d’une base de données consiste àdécider de ce qu’il est important d’intégrer au modèle. Traitez chaqueaspectdelaquestionsousformed’unobjet.Établissezunelistedetouslesobjetsauxquelsvouspouvezpenser.N’essayezpasencored’identifier lesrelations qui peuvent lier ces entités entre elles. Pour l’instant, essayezsimplementdedresserunelisteexhaustive.
Il est important de pouvoir bénéficier de l’aide de personnes quiconnaissent bien le système que vous allez tenter de modéliser. Vousobtiendrezdeprécieusesinformationsenlesincitantàparlerentreelleseten les interrogeant lors d’une séance de brainstorming. En travaillant demanière collective, vous développerez probablement une collectiond’objetspluscomplèteetplusprécisequ’enrestantdansvotrecoin.
Une fois que vous disposez d’un ensemble d’objets qui vous sembleraisonnablementcomplet,vouspouvezpasser à l’étape suivante : décidercommentcesobjetsserontreliésentreeux.Certainsdecesobjetssontdesentités majeures, totalement indispensables pour fournir les résultats que
vousescomptez.D’autressontsubordonnésàcesentitésprincipales.Enfin,certainsobjetsn’ontpeut-êtrefinalementrienàfairedansvotremodèleetdevrontêtreéliminésavantdevenir«polluer»labasededonnées.
Étape2:IdentifierlestablesetlescolonnesLes entités majeures se transforment en tables. Chacune possède unensemble d’attributs qu’il faut convertir en colonnes de la table. Parexemple,nombreusessontlesbasesdedonnéesd’entreprisequicontiennentune table CLIENTS pour conserver la trace du nom et de l’adresse desclients(plusévidemmentd’autresinformationsutiles).Chaqueattributd’unclient, tel que son nom, sa rue, sa ville, son code postal et son adresseInternet,esttransforméenunecolonnedelatableCLIENTS.
Il n’existe pas de règles générales vous aidant à identifier les objets quidevraient être des tables et à décider quels attributs ces tables doiventposséder.C’estàvousd’yréfléchir.Vousassocierezunattributàtelletablepour une certaine raison, et tel autre attribut à telle autre table pour uneraisondifférente.Basezvotredécisionsurcequevoussavezenrespectantdeuxobjectifs:
» Lesinformationsquevoussouhaitezpouvoirextrairedela
basededonnées.
» Commentvouscomptezutiliserlesinformations.
Lorsdelaconceptiondelastructuredestablesdevotrebasededonnées,ilest extrêmement important de prendre en considération l’avis des futursutilisateursainsiqueceluidespersonnesquiprendrontdesdécisionssurlabasedesinformationsqu’ellecontiendra.Si lastructure«raisonnable»àlaquelle vous arrivez ne correspond pas à lamanière dont les gens vontexploiterl’information,l’utilisationdevotresystèmeserévélerafrustranteet pourramêmedéboucher sur des prises de décision erronées.De tellesconséquencessontinacceptables!
Prenonsunexemplepourillustrerleprocessusintellectuelquidébouchesurlacréationd’unebasedotéedeplusieurstables.Supposonsquevousvenezde créerVetLab, un laboratoire demicrobiologie qui teste des spécimens
quevousfontparvenirdesvétérinaires.Ilestévidentquevousallezdevoirconserverlatracedenombreusesinformations,etnotamment:
» Lesclients.
» Lestestsquevouseffectuez.
» Lesemployés.
» Lescommandes.
» Lesrésultats.
Chacune de ces entités dispose d’attributs. Chaque client a un nom, uneadresse et d’autres informations sont nécessaires pour gérer les contacts.Chaquetestaunnometuncoût.Chaqueemployéadescoordonnéesainsiqu’un intitulé de poste et un salaire. Pour chaque commande, vous devezsavoirqui l’apassée,quandelleaétépasséeet surquel testelleportait.Pourchaquetest,vousdevezdisposerd’unnumérod’ordre,savoircequ’iladonné,etsilesrésultatsétaientpréliminairesoudéfinitifs.
Étape3:DéfinirlestablesVous devez maintenant définir une table par entité et une colonne parattribut.LeTableau5.1présentelestablesdeVetLab.
TABLEAU5.1LestablesdeVetLab.
Table Colonnes
CLIENTS Nomduclient
Adresse1
Adresse2
Ville
Etat
Codepostal
Téléphone
Fax
Contact
TESTS Nomdutest
Prixstandard
EMPLOYES Nomdel’employé
Adresse1
Adresse2
Ville
Etat
Codepostal
Téléphonepersonnel
Codebureau
Dated’embauche
Classification
Salariéhoraireousalariéoucommissionné
COMMANDES Numérodecommande
Nomduclient
Test
Responsablecommercial
Datedecommande
RESULTATS Numéro
Numérodecommande
Résultat
Datedeproduction
Préliminaireoudéfinitif
Vouspouvezcréercestablesàl’aided’unoutilRADoud’instructionsDDLdeSQL,delamanièresuivante:
CREATETABLSECLIENTS(
NOM_CLIENTCHARACTER(30)NOTNULL,
ADRESSE_1CHARACTER(30),
ADRESSE_2CHARACTER(30),
VILLECHARACTER(25),
ETATCHARACTER(2),
CODE_POSTALCHARACTER(10),
TELEPHONECHARACTER(13),
FAXCHARACTER(13),
CONTACTCHARACTER(30));
CREATETABLETESTS(
NOM_TESTCHARACTER(30)NOTNULL,
PRIX_STANDARDCHARACTER(30));
CREATETABLEEMPLOYES(
NOM_EMPLOYECHARACTER(30)NOTNULL,
ADRESSE_1CHARACTER(30),
ADRESSE_2CHARACTER(30),
VILLECHARACTER(25),
ETATCHARACTER(2),
CODE_POSTALCHARACTER(10),
TELEPHONE_PERSOCHARACTER(13),
CODE_BUREAUCHARACTER(4),
DATE_EMBAUCHEDATE,
CLASSIFICATIONCHARACTER(10),
HEUR_SAL_COMCHARACTER(1));
CREATETABLECOMMANDES(
NUMERO_COMMANDEINTEGERNOTNULL,
NOM_CLIENTCHARACTER(30),
TEST_COMMANDECHARACTER(30),
COMMERCIALCHARACTER(30),
DATE_COMMANDEDATE);
CREATETABLERESULTATS(
NUMERO_RESULTATINTEGERNOTNULL,
NUMERO_COMMANDEINTEGER,
RESULTATCHARACTER(50),
DATE_PRODUCTIONDATE,
PRELIMINAIRE_FINALCHARACTER(1));
Ces tables sont reliées entre elles par les attributs (colonnes) qu’ellespartagent,commesuit:
» LatableCLIENTSestliéeàlatableCOMMANDESparla
colonneNOM_CLIENT.
» LatableTESTSestliéeàlatableCOMMANDESparla
colonneNOM_TEST(TEST_COMMANDE).
» LatableEMPLOYESestliéeàlatableCOMMANDESparla
colonneNOM_EMPLOYE(COMMERCIAL).
» LatableRESULTATSestliéeàlatableCOMMANDESparla
colonneNUMERO_COMMANDE.
Pour qu’une table occupe vraiment un rôle dans une base de donnéesrelationnelle, il convient de la relier à une autre table par une colonnecommune.LaFigure5.1illustrelesrelationsentrenostables.
Les liens qui figurent sur la Figure 5.1 illustrent quatre relations un àplusieurs. Les losanges indiquent le lien de cardinalité entre chaque
extrémité d’une relation. Le chiffre 1 correspond au côté « un » desrelations,etlalettreNaucôté«plusieurs».
» Unclientpeutpasserplusieurscommandes,maischaque
commandeesteffectuéeparunetunseulclient.
» Chaquetestpeutfigurerdansplusieurscommandes,mais
chaquecommandecorrespondàunetunseultest.
» Chaquecommandeestenregistréeparunetunseul
employé(oucommercial),maischaquecommercialpeut
enregistrerplusieurscommandes(c’estpréférable).
FIGURE5.1LestablesdelabasededonnéesdeVetLab.
» Chaquecommandepeutdébouchersurplusieurs
résultatspréliminairesetsurunrésultatfinal,maischaque
résultatn’estassociéqu’àuneetuneseulecommande.
Commevouspouvezleconstatersurlafigure,l’attributquilieunetableàuneautrepeutporterunnomdifférentdanscestables.Cependantlesdeuxattributsdoiventavoirlemêmetypededonnées.
Domaines,jeuxdecaractères,interclassementsettranslationsBien que les tables soient les constituants principaux d’une base dedonnées, celle-ci comporte d’autres éléments. Dans le Chapitre 1, j’aidéfini ledomaine d’une colonne d’une table comme étant l’ensemble desvaleurs que peut prendre cette colonne. Une partie importante de laconception consiste à définir clairement des domaines de toutes lescolonnesàl’aidedecontraintes.
Les gens qui parlent anglais ne sont pas les seuls à utiliser des bases dedonnées.Ilestpossibled’utiliserdeslangagesdontlejeudecaractèresestdifférent de celui de l’anglais. SQL vous permet de spécifier le jeu decaractèresquevoussouhaitezutiliser.Enfait,vouspouvezmêmespécifierunjeudecaractèresdifférentpourchaquecolonned’unetable.SQLestl’undestrèsrareslangagesàoffrirunetellesouplesse.
Un interclassement, ou séquence d’interclassement, est un ensemble derègles qui spécifient comment les chaînes qui utilisent un certain jeu decaractèresdoiventêtrecomparéesentreelles.Chaquejeudecaractèresestdotéd’uninterclassementpardéfaut.DanslejeudecaractèresASCII,AestavantB etB est avantC.Une comparaison entre deux chaînesASCII sebaseradoncsurlefaitqueAestinférieuràBquiestinférieuràC.SQLvouspermetd’associer différents interclassements àun jeude caractères.Làencore,ilestl’undesrareslangagescapablesdecela.C’estuneraisonsupplémentairepouraimerSQL.
Dans une base, vous encodez parfois des données à l’aide d’un jeu decaractères,maisilpeutarriverquevoussouhaitiezlestraiterdansunautrejeu de caractères. Par exemple, vous disposez peut-être de données quiutilisent le jeudecaractèresallemand,maisvotre imprimantenegèrepaslescaractèresspécifiquesàcettelangue.UnetraductionestunefonctiondeSQL qui vous permet de traduire des chaînes de caractères d’un jeu decaractères à un autre. Par exemple, la traduction pourrait convertir uncaractèrespécifiquesousformededeuxlettres,commeleügermaniqueenueASCII.Ilestaussipossibledetransformerdescaractèresminusculesen
majuscules.Vouspouvezmêmeconvertirunalphabetdansunautre,commedel’arabeoudel’hébreuenASCII.
Améliorerlesperformancesàl’aidedesclésUne bonne règle à appliquer dès la conception spécifie que chaque ligned’une table doit pouvoir se distinguer de toutes les autres lignes de cettetable,c’est-à-direqu’elledoitêtreunique.Cetterèglepeutêtretransgresséeauxtablesquevousgénérezàl’occasionpourrépondreoccasionnellementàunbesoinspécifique,commeparexempleproduiredesstatistiquessurlabasedecritèresprécis.Mais elledoit s’appliquer à toutes les tablesquevouscomptezutiliseràdesfinsdiverses.
Une clé est un attribut ou une combinaison d’attributs qui identifie demanièreuniqueunelignedansunetable.Pouraccéderàunecertaineligne,il faut que vous disposiez d’un procédé permettant de la distinguer desautres. Du fait qu’elles sont uniques, les clés constituent un excellentmécanismed’accès.
Une clé ne doit jamais avoir une valeur nulle (c’est-à-dire vide ou nondéfinie). En effet, si vous utilisiez des clés nulles, deux lignes quicontiendraient des valeurs nulles dans les champsde la clé ne pourraientplussedistinguerl’unedel’autre.
Dans mon exemple de laboratoire vétérinaire, vous pouvez assigner àcertainescolonneslerôledeclé.NOM_CLIENTferaitunebonneclédansla table CLIENTS. Elle permettrait en effet de distinguer chaque client.NOM_TEST etNOM_EMPLOYE seraient de bonnes clés pour les tablesTESTSetEMPLOYES.NUMERO_COMMANDEetNUMERO_RESULTATreprésenteraient de bonnes clés pour les tables COMMANDES etRESULTATS.Danschaquecas,vérifiezquevousentrezunevaleuruniquepourchaqueligne.
Ilexistedeuxsortesdeclés:lesclésprimairesetlesclésétrangères.Lesclésdont jeviensdeparlersontdesclésprimaires.Cesclésgarantissentl’unicité.Jevaisparlerdesclésétrangèresdanslasectionsuivante.
Clésprimaires
Unecléprimaireestunecolonnedont lesvaleurs identifientchaque lignedelatabled’unemanièreunique.PourintroduirecettenotiondanslabasededonnéesVetLab,vouspouvezspécifierunecléprimaireaumomentoùvouscréezune table.Dans l’exemplesuivant,uneseulecolonnesuffit (ensupposantquetouslesclientsdeVetLabportentdesnomsdifférents):
CREATETABLECLIENTS(
NOM_CLIENTCHARACTER(30)PRIMARYKEY,
ADRESSE_1CHARACTER(30),
ADRESSE_2CHARACTER(30),
VILLECHARACTER(25),
ETATCHARACTER(2),
CODE_POSTALCHARACTER(10),
TELEPHONECHARACTER(13),
FAXCHARACTER(13),
CONTACTCHARACTER(30)
);
LacontraintePRIMARYKEYsesubstitueàlacontrainteNOTNULLquifiguraitdans ladéfinitionprécédentede la tableCLIENTS.Elle impliqued’ailleurs la contrainte NOTNULL, car une clé primaire ne peut jamaisprendreunevaleurnulle.
Bien que la plupart des SGBD autorisent la création de tables sans cléprimaire, toutes les tables d’une base devraient en posséder une. Pourappliquerceconcept,remplacezlacontrainteNOTNULLdanstoutesvostables. Dans notre exemple, les tables TESTS, EMPLOYES,COMMANDES et RESULTATS vont recevoir une contrainte PRIMARYKEY,commedansl’exemplesuivant:
CREATETABLETESTS(
NOM_TESTCHARACTER(30)PRIMARYKEY,
PRIX_STANDARDCHARACTER(30));
Il arrive parfois qu’aucune colonne ne suffise à elle seule à garantirl’unicité. Vous devez alors utiliser une clé composite. Il s’agit d’unecombinaison de colonnes qui, toutes ensemble, assurent cette unicité.
Supposezque certains des clients deVetLab soient des chaînes ayant descabinetsvétérinairesdansplusieursvilles.NOM_CLIENTn’estalorsplussuffisantpourdistinguerdeuxbureauxd’unmêmeclient.Vouspouvezalorsréglerleproblèmeendéfinissantuneclécompositedelamanièresuivante:
CREATETABLECLIENTS(
NOM_CLIENTCHARACTER(30)NOTNULL,
ADRESSE_1CHARACTER(30),
ADRESSE_2CHARACTER(30),
VILLECHARACTER(25)NOTNULL,
ETATCHARACTER(2),
CODE_POSTALCHARACTER(10),
TELEPHONECHARACTER(13),
FAXCHARACTER(13),
CONTACTCHARACTER(30),
CONSTRAINTBUREAUPRIMARYKEY
(NOM_CLIENT,VILLE)
);
ClésétrangèresUnecléétrangèreestunecolonne,ouungroupedecolonnes,dansunetablequicorrespondà(ouréférence)unecléprimairedansuneautretable.Unecléétrangèren’apasàêtreuniqueelle-même,maiselledoit identifierdemanièreuniquelaoulescolonnesqu’elleréférencedansl’autretable.
SilacolonneNOM_CLIENTestunecléprimairedanslatableCLIENTS,chaquelignedecettetabledoitprendreunevaleuruniquedanslacolonneNOM_CLIENT. NOM_CLIENT est une clé étrangère dans la tableCOMMANDES.CettecléétrangèrecorrespondàlacléprimairedelatableCLIENTS,maisellen’apasàêtreuniquedanslatableCOMMANDES.Etc’est tant mieux pour vous… Si chacun de vos clients vous passait unecommandepuiss’évanouissaitdanslanature,votrelaboratoireneferaitpaslongfeu.Sitoutvabien,denombreuseslignesdelatableCOMMANDESvont correspondre à chaque ligne de la tableCLIENTS, ce qui signifieraquepresquetousvosclientssontfidèlesàvotrelaboratoire.
La définition suivante de la table COMMANDES vous montre commentvous pouvez utiliser le concept de clé étrangère dans l’instructionCREATE:
CREATETABLECOMMANDES(
NUMERO_COMMANDEINTEGERPRIMARYKEY,
NOM_CLIENTCHARACTER(30),
TEST_COMMANDECHARACTER(30),
COMMERCIALCHARACTER(30),
DATE_COMMANDEDATE,
CONSTRAINTNOM_CEFOREIGNKEY(NOM_CLIENT)
REFERENCESCLIENTS(NOM_CLIENT),
CONSTRAINTTEST_CEFOREIGNKEY(TEST_COMMANDE)
REFERENCESTESTS(NOM_TEST),
CONSTRAINTSALES_CEFOREIGNKEY(COMMERCIAL)
REFERENCESEMPLOYES(NOM_EMPLOYE)
);
Dans cet exemple, les clés étrangères de la table COMMANDES lientcelle-ciauxclésprimairesdestablesCLIENTS,TESTSetEMPLOYES.
TravailleravecdesindexLa spécification SQL nementionne pas les index,mais cette omission nesignifiepaspourautantquelesindexsoientpeuutilisésniqu’ilssoientenoption dans un système de gestion de bases de données. Toutes lesimplémentationsdeSQLgèrent les index,maisd’unemanièrequi leurestpropre.DansleChapitre4,jevousaimontrécommentvouspouviezcréerun index en utilisantMicrosoftAccess, un outil de développement rapided’applications (RAD). Vous devrez vous référer à la documentation devotre système de gestion de bases de données (SGBD) pour comprendrecommentilimplémentelesindex.
Qu’est-cequ’unindex?
Lesdonnéesquecontientunetableapparaissentgénéralementdansl’ordredanslequelvouslesavezsaisies.Cependant,cetordrenecorrespondpastoujoursàceluidanslequelvouscompteztraiterlesdonnées.Parexemple,supposonsquevousvouliezaffichervotretableCLIENTSdansl’ordredeNOM_CLIENT.L’ordinateurdoitd’abordtrierlatabledanscetordre.Pluslatableestgrande,pluscetriprenddetemps.Quesepassera-t-ilsivotretablecontientunmilliondelignes?Iln’estpasrarequelecasseprésente.Même lesmeilleurs algorithmesde tri devront effectuer vingtmillionsdecomparaisonsetdesmillionsd’interversionspourtrierlatable.Mêmesurunordinateurtrèsrapide,vousalleztrouverletempsbienlong.
Les index vous permettent de gagner du temps. Un index est une tablesubsidiairequiestliéeàunetablededonnées.Pourchaquelignedecettedernière, il existe une ligne correspondante dans la table d’index.Cependant,l’ordredeceslignesestdifférentdansl’index.
LeTableau5.2vousmontreunexempledetablededonnées.
TABLEAU5.2TableCLIENTS.
NOM_CLIENT ADRESSE_1 ADRESSE_2 VILLE ETAT
CliniqueButternut
Animal
5,Butternut
Lane
Hudson NH
AmberVeterinary,
Inc
470KolvirCircle Amber MI
VetsRUs 2300Geoffrey
Road
Suite230 Anaheim CA
DocteurDoggie 32TerryTerrace Nutley NJ
Centreéquestre Département
vétérinaire
7890Paddock
Parkway
Gallup NM
Institut
océanographique
1002Marine
Drive
Key
West
FL
J.C.Campbell,
Vétérinaire
2500Maon
Street
Los
Angeles
CA
Fermeàversde
Wenger
15Bait
Boulevard
Sedons AZ
LeslignesnesontpastriéesparordrealphabétiqueselonNOM_CLIENT.Enfait,ellesnesontpastriéesdutout.Ellessontsimplementdansl’ordredanslequelquelqu’unlesasaisies.
UnindexpourlatableCLIENTSpeutressemblerauTableau5.3.
TABLEAU5.3L’indexparnomdeclientpourlatableCLIENTS.
NOM_CLIENT Pointeurverslatablededonnées
AmberVeterinary,Inc 2
CliniqueButternutAnimal 1
DocteurDoggie 4
Institutocéanographique 6
J.C.Campbell,Vétérinaire 7
Centreéquestre 5
VetsRUs 3
FermeàversdeWenger 8
L’indexcontientlechampsurlequelestbasél’index(iciNOM_CLIENT)etunpointeurverslatabledesdonnées.Cepointeurdonnelenumérodelalignecorrespondantedanslatablededonnées.
Pourquoiutiliserunindex?
Si jeveux traiterune tabledans l’ordreNOM_CLIENT,etque jedisposed’unindexarrangéseloncetordre,jepeuxeffectuertoutesmesopérationspresque aussi vite que si les données avaient été saisies en classantalphabétiquementlesnomsdesclients.Ilestpossibledeparcourirl’indexséquentiellement, et donc de récupérer ainsi successivement chaquepointeurversladonnéequiluicorresponddanslatable.
Si vous utilisez un index, le temps pris pour traiter la table seraproportionnelàN,oùNestlenombred’enregistrementsdanslatable.Sansindex, ce temps sera proportionnel à N lg N, où N est le logarithmebase2deN.Ladifférencen’estpassignificativesilatableestpetite,maiselleledevientdèslorsquesatailleestvolumineuse.Certainesopérationsnepeuventêtreenvisagéessansindexerlestables.
Supposons par exemple que vous disposiez d’une table quicontient1000000d’enregistrements(N=1000000)etquetraiterchaqueenregistrementprenneunemilliseconde(unmillièmedeseconde).Sivousutilisez un index, le traitement de la table entièredemandera 1 000 secondes, soit à peu près 17 minutes. Sans index, cetraitement prendra 1 000 000 x 20 millisecondes, soit 20 000 secondes,c’est-à-direàpeuprès5heuresetdemie.Jepensequevousconviendrezdufaitqueladifférenceestsubstantielle.
TenirunindexàjourUne fois que vous avez créé un index, vous devez le tenir à jour. Fortheureusement,votreSGBDassureracettemaintenancechaquefoisquevousmodifierezlatablededonnéesassociée.Cetravailprendunpeudetemps,maiscelaenvaut lapeine.Lorsquevousaurezcrééun indexetquevotreSGBD lemaintiendra à jour, cet index seradisponible à tout instant pouraccélérerletraitementdedonnées.
Lemeilleurmomentpourdéfinirunindexestceluioùvouscréezlatableàlaquelleilestassocié.Decettemanière,vousn’aurezpasàsouffrirdelalongue attente inhérente à la création d’un index quand une table est déjàrempliededonnées.Essayeztoujoursdeprévoiràl’avancevosbesoinsenmatière d’accès aux données. Définissez alors un index pour chaquepossibilité.
CertainsSGBDvouspermettentdedésactiverlamaintenancedesindex.Ilpeutêtreutiledelefairedanslecontexted’applicationstempsréeloùcette
miseàjourconsommetropdetempspourlepeudedisponibilitésdontvousdisposez («Désolé,chef, il fautarrêter lecompteà reboursde lanavetteparce que les index ne sont pas à jour ! »). Il arrive parfois que vouspuissiezprogrammer lamiseà jourdes indexàdesheuresoù labaseestpeusollicitée.
Ne tombez pas dans le piège d’ajouter un index pour optimiser desrecherchesauxquellesvousallezrarementprocéder.Gérerun indexprenddu temps, car c’est une opération supplémentaire que l’ordinateur doitaccomplirchaquefoisqu’ilmodifielechampindexé,qu’ilajouteouqu’ilsupprime une ligne. Ne créez des index que pour des tables de tailleimportante, et pour optimiser des recherches auxquelles vous comptezprocédersouvent.Sinon,lesperformancesdevotresystèmes’entrouverontdégradées.
Ilpeutarriverquevousayezàréaliserunrapportannueloutrimestrieldontlaproductionprendraittropdetempssiellenes’appuyaitpassurunindex(qui ne vous sert d’ailleurs qu’à cette occasion). Créez cet index justeauparavant,produisez le rapport,puis supprimez l’indexde sortequ’ilneperturbepasletravailduSGBDjusqu’àlaprochainedemandederapport.
Maintenirl’intégritéUne base de données n’est utile que si vous êtes certain que les donnéesqu’elle contient sont correctes. Par exemple, la présence de donnéeserronéesdansunebasededonnéesmédicale,aéronautiqueoumilitairepeutdéboucher sur la mort d’autrui. Le concepteur d’une base de donnéesdevrait être en permanence certain qu’il est impossible à des donnéesinvalidesdepénétrerlabase.
Certes,cetobjectifn’estpastoujoursréalisableentotalité.Parcontre,ilesttoujours possible de s’assurer (au moins) que les valeurs saisies sontvalides.Maintenirl’intégritédesdonnéessignifies’entourerdetouteslesgaranties pour que tout ce qui est entré dans la base satisfasse auxcontraintes qui ont été établies auparavant. Si, par exemple, un certainchampestdutypeDate,leSGBDdevraityrejetertoutetentativedesaisied’unevaleurautrequ’unedatevalide.
Certains problèmes ne peuvent pas être stoppés au niveau de la base dedonnées.Leprogrammeurdel’applicationdoitlesintercepteravantqu’ilsn’endommagentlabasededonnées.Toutepersonnechargéedemanipulerla
base de données doit bien être consciente des dangers qui menacentl’intégrité de cette dernière et prendre les mesures qui s’imposent pourdésactivercesfailles.
L’intégrité d’une base de données peut relever de plusieurs types. Et denombreux problèmes sont susceptibles d’affecter cette intégrité. Dans lessections suivantes, je traite de trois types d’intégrité : l’intégrité del’entité, l’intégrité du domaine et l’intégrité référentielle. Nous verronségalementquelques-unesdesmenacesquiplanentsurcetteintégrité.
L’intégritédel’entitéChaquetabled’unebasededonnéescorrespondàuneentitédumonderéel.Cette entité peut être physique ou conceptuelle, mais, d’une certainemanière,sonexistenceest indépendantedecelledelabase.L’intégritédel’entitéd’unetableestassuréequandlatableesttotalementcohérenteavecl’entité qu’elle représente. Pour cela, la table doit disposer d’une cléprimaire.Celle-ciidentifiechaquelignedelatable.Sanscléprimaire,vousnepouvezpasêtrecertainqu’unelignerécupéréesoitlabonne.
Pour maintenir cette intégrité, vous devez spécifier que la colonne ou legroupedecolonnesquiconstituelacléprimaireestNOTNULL.Deplus,vous devez contraindre la clé primaire pour qu’elle soit UNIQUE.Certaines implémentations de SQL vous permettent de mentionner cettecontraintelorsdeladéclarationdelatable.D’autresnelepermettentpas,si bienquevousdevez la spécifier après avoir spécifié comment ajouter,modifieretsupprimerdesdonnéesd’unetable.LameilleuresolutionpourvousassurerquevotrecléprimaireestàlafoisNOTNULLetUNIQUEestdespécifierlacontraintePRIMARYKEYlorsquevouscréezlatable,commedansl’exemplesuivant:
CREATETABLECLIENTS(
NOM_CLIENTCHARACTER(30)PRIMARYKEY,
ADRESSE_1CHARACTER(30),
ADRESSE_2CHARACTER(30),
VILLECHARACTER(25),
ETATCHARACTER(2),
CODE_POSTALCHARACTER(10),
TELEPHONECHARACTER(13),
FAXCHARACTER(13),
CONTACTCHARACTER(30)
);
Uneautre solutionconsisteàutiliserNOTNULLavecUNIQUE, commedansl’exemplesuivant:
CREATETABLECLIENTS(
NOM_CLIENTCHARACTER(30)NOTNULL,
ADRESSE_1CHARACTER(30),
ADRESSE_2CHARACTER(30),
VILLECHARACTER(25),
ETATCHARACTER(2),
CODE_POSTALCHARACTER(10),
TELEPHONECHARACTER(13),
FAXCHARACTER(13),
CONTACTCHARACTER(30)
);
L’intégritédudomaineEngénéral, vous ne pouvez pas garantir qu’une donnée particulière de labasededonnéesseracorrecte,maisvouspouvezdumoinsvousassurerdesa validité. De nombreuses données ne peuvent prendre qu’un certainnombredevaleurs.Sivousremarquezuneentréequineprendpasunedecesvaleurspossibles,c’estqu’elleesterronée.Parexemple,lesÉtats-Unispossèdent 50 États plus le district deColumbia, PuertoRico et quelquesautrespossessions.Chacunedecesrégionsestdésignéeparuncodeàdeuxlettresreconnuparlesservicespostaux.SivotrebasededonnéescontientunecolonneETAT,vouspouvezassurerl’intégritédudomaineenspécifiantquetouteentréedanslacolonneETATdoitêtrel’undecescodesàdeuxlettres.Siquelqu’unsaisitunevaleurquinefaitpaspartiedecetteliste,ilenfreintl’intégritédesdonnées.Sivoustestezl’intégritédevotredomaine,
vous pouvez refuser d’accepter toute opération qui provoque ce genre debrèche.
L’intégrité du domaine peut être menacée si vous ajoutez une nouvelledonnéeàunetableenutilisantl’unedesinstructionsINSERTouUPDATE.Vous pouvez spécifier le domaine d’une colonne en utilisant l’instructionCREATE DOMAIN avant d’utiliser cette colonne dans une instructionCREATETABLE,commedansl’exemplesuivant:
CREATEDOMAINLEAGUE_DOMCHAR(8)
CHECK(LEAGUEIN(‘Américaine’,‘Nationale’));
CREATETABLETEAM(
TEAM_NAMECHARACTER(20)NOTNULL,
LEAGUECHARACTER(8)NOTNULL
);
Le domaine de la colonne LIGUE contient seulement deux valeursvalides:AméricaineetNationale.VotreSGBDrefuseradevaliderla saisie ou de modifier une ligne de la table EQUIPES si la colonneLIGUEneprendpasl’unedecesdeuxvaleurs.
L’intégritéréférentielleMême si l’intégrité de l’entité et du domaine de chaque table de votresystèmeest assurée, vouspouvez toujours être confronté àdesproblèmesparce que les relations qui relient vos tables sont incohérentes. Dans laplupartdesbasesdedonnéesbienconçues,chaquetablecontientaumoinsunecolonnequiseréfèreàunecolonnedansuneautretable.Cesréférencessont importantes pour maintenir l’intégrité de la base de données. Pourautant,ellesfavorisentl’apparitiond’anomalieslorsdesmodifications.
Lesanomaliesdemodificationsontdesproblèmesquiseproduisentquandvousmodifiezunedonnéedansuneligned’unetable.
Les relations entre les tables ne sont généralement pas bidirectionnelles.Unetabledépendnormalementdel’autre.Supposonsparexemplequevousdisposiez d’une base de données qui contient des tables CLIENTS et
COMMANDES.VouspourriezsaisirunclientdanslatableCLIENTSavantqu’il ait passé une commande.Cependant, vous ne pouvez pas saisir unecommandedansCOMMANDEStantqueleclientn’apasétécréédanslatable CLIENTS. Ce type de relation est nommé relation parent-enfant, latable CLIENTS étant la table parent et la table COMMANDES la tableenfant.L’enfantdépendduparent.
Généralement, la clé primaire de la table parent est une colonne (ou ungroupedecolonnes)quiapparaîtdanslatableenfant.Àl’intérieurdecettetable enfant, elle (la colonne) ou il (le groupe de colonnes) est une cléétrangère.Unecléétrangèrepeutprendreunevaleurnulleetn’apasàêtreunique.
Les anomalies dans les modifications surviennent de plusieurs manières.Parexemple,unclientdéménageetvousvoulezleretirerdevotrebasededonnées. S’il a déjà passé des commandes (enregistrées) dans la tableCOMMANDES,cettesuppressionvaengendrerdesproblèmes.Eneffet,ilexistera alors des enregistrements dans la table COMMANDES (enfant)pour lesquels il n’existe pas d’enregistrement dans la table CLIENTS(parent). Des problèmes de cette nature peuvent aussi survenir si vousajoutez un enregistrement à une table enfant sans effectuer les ajoutscorrespondantsàlatableparent.
Lesclésétrangèresde toute tableenfantdoivent refléter lesmodificationsapportéesàlacléprimairecorrespondantedelatableparent,sansquoiilyauraanomaliedemodification.
Lessuppressionsencascade–àutiliseravecsoinVous pouvez vous prémunir contre presque tous les problèmes d’intégritéréférentielle en contrôlant avec soin le processus de mise à jour. Danscertainscas,vousdevezrépercuterencascadelessuppressionsdelatableparent dans ses tables enfants. Si vous supprimez une ligne de la tableparent, vous devez alors supprimer toutes les lignes de ses tables enfantsquicontiennentunecléétrangèrecorrespondantàlacléprimairequevousvenez de supprimer dans la table parent. Prenons un exemple pourmieuxcomprendreceprocessus:
CREATETABLECLIENTS(
NOM_CLIENTCHARACTER(30)PRIMARYKEY,
ADRESSE_1CHARACTER(30),
ADRESSE_2CHARACTER(30),
VILLECHARACTER(25)NOTNULL,
ETATCHARACTER(2),
CODE_POSTALCHARACTER(10),
TELEPHONECHARACTER(13),
FAXCHARACTER(13),
CONTACTCHARACTER(30)
);
CREATETABLETESTS(
NOM_TESTCHARACTER(30)PRIMARYKEY,
PRIX_STANDARDCHARACTER(30)
);
CREATETABLEEMPLOYES(
NOM_EMPLOYECHARACTER(30)PRIMARYKEY,
ADRESSE_1CHARACTER(30),
ADRESSE_2CHARACTER(30),
VILLECHARACTER(25),
ETATCHARACTER(2),
CODE_POSTALCHARACTER(10),
TELEPHONE_PERSOCHARACTER(13),
CODE_BUREAUCHARACTER(4),
DATE_EMBAUCHEDATE,
CLASSIFICATIONCHARACTER(10),
HEUR_SAL_COMCHARACTER(1)
);
CREATETABLECOMMANDES(
NUMERO_COMMANDEINTEGERPRIMARYKEY,
NOM_CLIENTCHARACTER(30),
TEST_COMMANDECHARACTER(30),
COMMERCIALCHARACTER(30),
DATE_COMMANDEDATE
CONSTRAINTNOM_CEFOREIGNKEY(NOM_CLIENT)
REFERENCESCLIENTS(NOM_CLIENT)
ONDELETECASCADE,
CONSTRAINTTEST_CEFOREIGNKEY(TEST_COMMANDE)
REFERENCESTESTS(NOM_TEST)
ONDELETECASCADE,
CONSTRAINTVENTES_CEFOREIGNKEY(COMMERCIAL)
REFERENCESEMPLOYES(NOM_EMPLOYE)
ONDELETECASCADE
);
La contrainteNOM_CEdésigneNOM_CLIENTcomme clé étrangère quiréférence la colonne NOM_CLIENT dans la table CLIENTS. Si voussupprimez une ligne dans la table CLIENTS, vous détruisez alorsautomatiquement toutes les lignes de la table COMMANDES dont lacolonne NOM_CLIENT contient la même valeur que la colonneéquivalente de la table CLIENTS. La suppression se déroule en cascadedepuislatableCLIENTSjusqu’àlatableCOMMANDES.IlenvademêmepourlesclésétrangèresdanslatableCOMMANDESquiseréfèrentàdesclésprimairesdanslestablesTESTSetEMPLOYES.
D’autresmanièredecontrôlerlesanomaliesdemiseàjourVouspourriezpréféreràcettesuppressionencascadeuneautresolution,quiconsiste à passer la valeur NULL dans les clés étrangères d’une tableenfant.Considérezlavariantesuivantedel’exempleprécédent:
CREATETABLECOMMANDES(
NUMERO_COMMANDEINTEGERPRIMARYKEY,
NOM_CLIENTCHARACTER(30),
TEST_COMMANDECHARACTER(30),
COMMERCIALCHARACTER(30),
DATE_COMMANDEDATE
CONSTRAINTNOM_CEFOREIGNKEY(NOM_CLIENT)
REFERENCESCLIENTS(NOM_CLIENT)
CONSTRAINTTEST_CEFOREIGNKEY(TEST_COMMANDE)
REFERENCESTESTS(NOM_TEST)
CONSTRAINTVENTES_CEFOREIGNKEY(COMMERCIAL)
REFERENCESEMPLOYES(NOM_EMPLOYE)
);
LacontrainteVENTES_CEdésignelacolonneCOMMERCIALcommecléétrangèreréférençantlacolonneNOM_EMPLOYEdelatableEMPLOYES.Si un commercial quitte la société, vous supprimez sa lignedans la tableEMPLOYES.Unnouvel employéprendra probablement la place de celuiquivientdepartir,maispourl’instantlasuppressiondunomducommercialde la table EMPLOYES entraîne le passage à NULL de la colonneCOMMERCIALdescommandesqu’iltraitait.
Il est aussi possible d’empêcher l’intrusion de données invalides ouinconsistantesdansunebaseenutilisantl’unedecesméthodes:
» Refusezd’autorisertoutajoutdansunetableenfant
tantqu’iln’existepasdelignecorrespondantedansla
tableparent.Vouséviterezainsil’ajoutdelignes
«orphelines»danslatableenfant.Decettemanière,vous
aiderezàconserverdestablescohérentes.
» Refusezquelacléprimaired’unetablepuisseêtre
modifiée.Decettemanière,vousn’aurezplusàmettreà
jourdesclésétrangèresdansd’autrestablesquidépendent
decettecléprimaire.
Lejouroùvousavezpenséque
toutétaitfini…Laseulechosedontonpeutêtresûrdanslavieréelle,c’estduchangement.Danslemondedesbasesdedonnées,c’estpareil.Vousavezcrééunebase,vousavezdéfinivostables,voscontraintes,vousavezremplideslignesetdeslignesdedonnées…Etc’estàcetinstantquel’ordretombed’enhaut:lastructuredoitêtrechangée.Commentajouterunenouvellecolonneàunetable existante ?Comment en supprimer une qui est devenue inutile ?Nepaniquezpas:SQLestlà!
AjouterunecolonneàunetableexistanteSupposonsquevotresociétédécidequechaqueanniversaired’unmembredupersonneldevraêtrefêté.Uncoordinateurestnomméàceteffet.Pourluipermettredeplanifiercespetitessauteries,vousdevezajouterunecolonneDATE_NAISSANCE à la table EMPLOYES. Pas de problème ! Il voussuffitdefaireappelàl’instructionALTERTABLE.Voicicomment:
ALTERTABLEEMPLOYES
ADDCOLUMNDate_AnniversaireASDATE;
Iln’yaplusqu’àsaisirlabonnedatedenaissancedanschaquelignedelatable,etc’estpartipourlesagapes…
Supprimerunecolonned’unetableexistanteLesaffairesvontmal,etvotreentreprisen’aplus lesmoyensd’offrirunepetitefêteàsespersonnelslejourdeleuranniversaire.Plusdechampagne,plusdedatesdenaissance…Làencore,l’instructionALTERTABLEvouspermetdefairefaceàcettedouloureusesituation:
ALTERTABLEEMPLOYES
DROPCOLUMNDate_Anniversaire;
Aumoins,vousenavezprofitétantquelesaffairesmarchaientbien!
SourcespotentiellesdeproblèmesL’intégrité de votre base de données est menacée par toutes sortes deproblèmes.Certainsd’entreeuxneseposentqu’avecdesbasesdedonnéesqui contiennent plusieurs tables, tandis que d’autres peuvent surgirmêmeavecdesbasesdedonnéesnecomprenantqu’uneseuletable.
MauvaisesaisieLesdocumentsoulesfichiersquevousutilisezpouralimentervotrebasededonnées peuvent contenir des données erronées (qu’il s’agissed’informations valides mais qui ont été corrompues ou de valeursparfaitement indésirables). Des tests aux limites vous permettront devérifierqueladonnéenemenacepasl’intégritédudomaine.Cependant,cetypedetestneprévientpastouslesproblèmes.Lesvaleursquisetrouventdansleslimitesautoriséesmaisquisontnéanmoinserronéesneserontpasdétectées.
Erreurdel’opérateurLadonnéeàsaisirpeutêtrecorrecte,maisl’opérateurlatranscritmal.Cetype d’erreur peut conduire aux mêmes problèmes que ceux posés parl’utilisation de données erronées. Là encore, un test aux limites peutprévenirenpartiecetteerreur.Unemeilleuresolutionseraitqu’unsecondopérateur valide les saisies du premier. Cependant, c’est une solutioncoûteuse, car vous devrez doubler à la fois vos effectifs et le temps desaisie. Mais dans certaines circonstances ce sacrifice peut parfois vouséviterdeperdreplusqu’ilnevouscoûte.
PannemécaniqueSiunepannemécaniquesurvient,tellequelecrashd’undisquequandunetable est ouverte, les données qui se trouvent dans la table peuvent êtredétruites.Votreseulesolutionestderéaliserdessauvegardesfréquentes.
MalveillanceQuelqu’un pourrait vouloir volontairement corrompre vos données. Votrepremièrelignededéfenseseraderefuserl’accèsàvotrebaseàquiconque
pourrait faire preuve de malveillance et de limiter les droits des autrespersonnes au strict nécessaire. Votre seconde ligne de défense sera destocker des sauvegardes en lieu sûr. Testez régulièrement la sécurité devotreinstallation.Celanefaitpasdemald’êtreunpeuparanoïaque.
RedondancededonnéesLaredondancededonnées est un problème connu dumodèle de base dedonnées hiérarchique, mais il peut aussi affecter des bases de donnéesrelationnelles.Cette redondancegaspille de l’espacede stockage, ralentitlestraitementsetpeutcorrompresérieusementlesdonnées.Sivousstockezlamêmedonnéedansdeuxtablesdifférentes,unemodificationdelacopiedecettedonnéedansunetablepeutnepasêtrerépercutéedansl’autre.Ilyaalorsincohérencepuisqu’iln’estpastoujourspossiblededirequelleestla bonne information. Il faut donc limiter autant que faire se peut laredondancedesdonnées.
Il faut certes un peu de redondance, ne serait-ce que pour que la cléprimaired’unetableservedecléétrangèredansuneautre table,maispastrop.L’unedessolutionslesplusefficacespourlimiterlaredondanceestlanormalisation, qui consiste à découper une table en plusieurs tables plussimples.
Unefoisquevousaurezéliminélaredondancedevotremodèlededonnées,vous réaliserez peut-être que les performances sont insuffisantes. Lesopérateurs ont souvent recours à la redondance pour accélérer lestraitements. Dans l’exemple précédent de la base de VetLab, la tableCOMMANDES contient seulement le nom du client pour identifier lasourcedechaquecommande.Sivouspréparezunecommande,vousdevezeffectuerla jointuredestablesCLIENTSetCOMMANDESafind’obtenirl’adresse du client. Si cette jointure vous semble prendre trop de temps,vouspourriezstockerl’adresseduclientdanslatableCOMMANDES.Laredondanceainsicrééepermetdeneplusrecouriràlajointureetaccélèredonc lapréparationd’unecommande.Encontrepartie, l’efficacitéglobaledu système sera légèrement dégradée, et lamise à jour des adresses desclientsseraplusdélicate.
Lesutilisateursconçoiventsouventdesbasesdedonnéesavecunminimumderedondanceetunhautdegrédenormalisation.Lorsqu’ilsconstatentquelesperformancesd’applicationsimportantessontmauvaises,ilsdécidentdedénormaliser leurs bases et d’y introduire sélectivement une certaineredondance.Lemotimportantesticisélectivement.Vousdevezprendredes
mesures appropriées pour que la redondance ne provoque pas plus deproblèmesqu’ellen’enrésout.Pourplusd’informations,voyezplusloinlasectionconsacréeàlanormalisation.
DépassementdelacapacitéduSGBDUnsystèmedebasesdedonnéespeutfonctionnerparfaitementpendantdesannées.Puisdeserreurscommencentàseproduiredetempsàautre.Etcesproblèmesdeviennentdeplusenplussérieux.C’estpeut-êtrelesignequevous approchez des limites de votre système. Le nombre des lignescontenues dans une table n’est en aucun cas infini. De même, il y a deslimitesauxcontraintes,aunombredecolonnes,etainsidesuite.ComparezlatailleetlecontenudevotrebasededonnéesauxspécificationsdevotreSGBD. Si vous vous rapprochez du point de rupture, il va vous falloirenvisager une mise à niveau vers un système plus puissant. Une autresolutionpourraitconsisteràarchiverlesdonnéeslesplusanciennes(cellesqui ne sont plus exploitées, celles qui servent uniquement à conserver lamémoiredevosactivitésetàétablirdesstatistiques),puisàlessupprimerdevotrebase.
ContraintesCi-avantdanscechapitre,j’aiparlédescontraintescommedemécanismesqui permettent de vous assurer que les données saisies dans une colonned’une table appartiennent bien à la plage de valeurs autorisées. UnecontrainteestunerèglequeleSGBDapplique.Unefoislabasededonnéesdéfinie,vouspouvezincluredescontraintes(tellesqueNOTNULL)dansla définition des tables. Il est alors de la responsabilité du SGBDd’interdiretoutetransactionquivioleraitunecontrainte.
Ilexistetroistypesdecontraintes:
» Unecontraintedecolonneimposeuneconditionàune
colonnedansunetable.
» Unecontraintedetablesappliqueàunetabletout
entière.
» Uneassertionestunecontraintequiportesurplusieurs
tables.
ContraintesdecolonneVoiciunexempledecontraintedecolonnedansuneinstructionDDL:
CREATETABLECLIENTS(
NOM_CLIENTCHARACTER(30)NOTNULL,
ADRESSE_1CHARACTER(30),
ADRESSE_2CHARACTER(30),
VILLECHARACTER(25),
ETATCHARACTER(2),
CODE_POSTALCHARACTER(10),
TELEPHONECHARACTER(13),
FAXCHARACTER(13),
CONTACTCHARACTER(30)
);
L’instruction applique la contrainte NOT NULL à la colonneNOM_CLIENT,cequisignifiequecettecolonnenepeutcontenirunevaleurnulle. Vous pourriez aussi appliquer la contrainteUNIQUE. Elle spécifiequechaquevaleurdecettecolonnedoitêtreuniquedanstoutelatable.Lacontrainte CHECK est particulièrement utile parce qu’elle peut prendren’importequelleexpressionvalideenargument.Parexemple:
CREATETABLETESTS(
NOM_TESTCHARACTER(30)NOTNULL,
PRIX_STANDARDNUMERIC(6,2)
CHECK(PRIX_STANDARD>=0.0
ANDPRIX_STANDARD<=200.0)
);
Lecoûtd’un testdeVetLabdoit toujoursêtresupérieurouégalàzéro.Etaucuntestnedoitcoûterplusde200euros.LaclauseCHECK refuse toutmontant qui n’appartient pas à la plage 0 <= PRIX_STANDARD
<= 200. Vous pourriez aussi spécifier cette contrainte de la manièresuivante:
CHECK(PRIX_STANDARDBETWEEN0.0AND200.0)
ContraintesdetableLa contrainte PRIMARY KEYspécifie que la colonne à laquelle elles’appliqueestunecléprimaire.Cettecontrainte s’imposedoncà la tableentière et est l’équivalent d’une combinaison des contraintes de colonnesNOTNULL et UNIQUE.Vous pouvez spécifier cette contrainte dans uneinstructionCREATE,commedansl’exemplesuivant:
CREATETABLECLIENTS(
NOM_CLIENTCHARACTER(30)PRIMARYKEY,
ADRESSE_1CHARACTER(30),
ADRESSE_2CHARACTER(30),
VILLECHARACTER(25),
ETATCHARACTER(2),
CODE_POSTALCHARACTER(10),
TELEPHONECHARACTER(13),
FAXCHARACTER(13),
CONTACTCHARACTER(30)
);
Lescontraintesnommées, tellesqueNOM_CEdans l’exempledonnédans« Les suppressions en cascade – à utiliser avec soin » peuvent avoirquelquesfonctionnalitéssupplémentaires.Parexemple,supposonsquevoussouhaitiez charger quelques centaines de prospects dans votre tablePROSPECT. Vous disposez d’un fichier qui contient essentiellement desprospects des États-Unis, mais on trouve aussi quelques prospectscanadiens perdus dans le fichier. Normalement, vous souhaiteriezrestreindrevotretablePROSPECTpourn’yfairefigurerquelesprospectsaméricains, mais vous ne voulez pas que le chargement soit interrompu
chaque fois qu’il tombe sur un canadien (les codes postaux canadienscomprennentdeslettresetdeschiffres,mais lescodespostauxaméricainsnecontiennentquedeschiffres).VouspouvezchoisirdenepasactiverdecontraintesurCODE_POSTALtantquelechargementn’estpasterminé,etd’activerlacontrainteensuite.
Audépart,votretablePROSPECTaétécrééeenutilisantcettecommandeCREATETABLE:
CREATETABLEPROPECT(
NOM_CLIENTCHARACTER(30)PRIMARYKEY,
ADRESSE_1CHARACTER(30),
ADRESSE_2CHARACTER(30),
VILLECHARACTER(25),
ETATCHARACTER(2),
CODE_POSTALCHARACTER(10),
TELEPHONECHARACTER(13),
FAXCHARACTER(13),
CONTACTCHARACTER(30)
CONSTAINTZIPCHECK(CODE_POSTALBETWEEN0AND
99999)
);
Avantlechargement,vouspouvezdésactiverlacontrainteZIP:
ALTERTABLEPROSPECT
CONSTRAINTZIPNOTENFORCED;
Unefoisquelechargementestterminé,vouspouvezréactiverlacontrainte:
ALTERTABLEPROSPECT
CONSTRAINTZIPENFORCED;
À cet instant, vous pouvez éliminer les lignes qui ne répondent pas à lacontrainteavec:
DELETEFROMPROSPECT
WHERECODE_POSTALNOTBETWEEN0AND99999;
LesassertionsUne assertion spécifie une restriction portant sur plusieurs tables.L’exemplesuivantutiliseuneconditionderecherchequiextraitdesvaleursdedeuxtablespourcréeruneassertion:
CREATETABLECOMMANDES(
NUMERO_COMMANDEINTEGERNOTNULL,
NOM_CLIENTCHARACTER(30),
TEST_COMMANDECHARACTER(30),
COMMERCIALCHARACTER(30),
DATE_COMMANDEDATE);
CREATETABLERESULTATS(
NUMERO_RESULTATINTEGERNOTNULL,
NUMERO_COMMANDEINTEGER,
RESULTATCHARACTER(50),
DATE_PRODUCTIONDATE,
PRELIMINAIRE_FINALCHARACTER(1));
CREATEASSERTION
CHECK(NOTEXISTSSELECT*FROMCOMMANDES,
RESULTATS
WHERECOMMANDE.NUMERO_COMMANDE=
RESULTATS.NUMERO_COM-
MANDE
ANDCOMMANDES.DATE_COMMANDE>
RESULTATS.DATE_PRODUCTION)
;
Cette assertion vous garantit qu’aucun résultat n’est transmis si lacommandecorrespondanten’apasétévalidée.
NormaliserlabasededonnéesCertaines méthodes d’organisation des données sont meilleures qued’autres. Il y en a qui sont plus logiques.D’autres qui sont plus simples.Certaines permettent d’éviter l’apparition d’incohérences quand vouscommencezàutiliserlabase.
LesanomaliesdemodificationetlesformesnormalesNombredeproblèmes(appelésanomaliesdemodification)sontcapablesde « pourrir » une base de données que vous n’aurez pas correctementstructurée.Pourleséviter,vouspouveznormaliserlastructuredelabasededonnées. La normalisation consiste généralement à découper une table endeuxtablesplussimples.
Les anomalies de modification sont ainsi nommées parce qu’elles sontgénéréeslorsdel’ajout,delamodificationoudelasuppressiondedonnéesdansunetable.
Pourcomprendrecommentellespeuventsurvenir,observezlaFigure5.2.
Votresociétécommercialisedesproduitsd’entretienménagersetd’hygiènepersonnelle. Pour chaque produit, vous facturez lemême prix à tous vosclients. La table VENTES conserve la trace de toutes les transactions.Supposezmaintenantque laréférence1001déménageetnesoitdoncplusundevosclients.Cequ’ilaachetéparlepassénevousintéresseplus.Vousvoulez retirer sa ligne de la table. Mais en effectuant cette suppression,vousn’allezpasseulementoublierqueleclient1001aachetédelapoudreàlaver;vousallezaussi«oublier»quecettepoudrecoûte12euros.Cettesituation est appelée anomalie de suppression. En supprimant un fait (leclient1001aachetédelapoudreàlaver),vousallezeneffacerunautreparinadvertance(leprixdelapoudreenquestion).
FIGURE5.2LatableVENTES.
Lamême tablepermetdemontrer cequ’estuneanomalied’insertion.Parexemple, supposons que vous désiriez ajouter un déodorant à 2 euros àvotre inventaire. Vous ne pouvez pas ajouter cette donnée dans la tableVENTES,carpersonneencoren’aachetéceproduit.
Le problème avec notre table VENTES est qu’elle traite de tropd’informationsenmêmetemps.Elleenregistre lesproduitsque lesclientsachètent et le prix de ces produits. Vous devez donc scinder la table endeux, chaquenouvelle table s’occupantd’un thèmeoud’une idée, commesurlaFigure5.3.
LaFigure5.3vousmontrelerésultatdeladivisiondelatableVENTESendeuxnouvellestables:
» ACHAT_CLIENTtraitedelaseuleidéed’unachatd’un
client.
» PRIX_PRODUITtraitedelaseuleidéeduprixd’unproduit.
FIGURE5.3LatableVENTESestdécoupéeendeuxtables.
Vouspouvezmaintenantsupprimer la lignequiconcerne leclient1001deACHAT_CLIENT sans perdre le prix de la poudre à laver. CetteinformationsetrouvemaintenantdanslatablePRIX_PRODUIT.Ildevientaussipossibled’ajouter ledéodorantàPRIX_PRODUITqu’ilaitdéjàétévenduounon.Lesinformationsrelativesauxachatssontstockéesailleurs,dansACHAT_CLIENT.
Le processus qui consiste à découper une table en plusieurs tables dontchacunetraited’unthèmeparticulierestappelénormalisation.Unprocessusdenormalisationquirésoutunproblèmenerèglepasforcémentlesautres.Pour les résoudre tous, il vous faudra probablement découper encore lestables jusqu’à ce que chacune ne s’occupe plus que d’une seule idée.Chaquetabledevraitdoncprendreenchargeunetunseulthèmeprincipal.Parfois, ilestvéritablementdifficilededéterminersiunetabletraited’unoudeplusieursthèmes.
Vous pouvez classer les tables en fonction du type d’anomalies demodification auquel elles sont sujettes. Dans un document de 1970 quidécritpourlapremièrefoislemodèlerelationnel,E.F.Coddidentifietroissourcesd’anomaliesdemodificationetdéfinitlapremière,ladeuxièmeetlatroisièmeformenormale(1NF,2NFet3NF)pourlesprévenir.Danslesannéessuivantes,Coddetd’autreschercheursontdécouvertd’autrestypesd’anomaliesetont spécifiédenouvelles formesnormalespour les traiter.La forme normale de Boyce-Codd (BCNF), la quatrième forme normale(4NF) et la cinquième forme normale (5NF) offrent chacune un degrésupérieurdeprotectioncontrelesanomaliesdemodification.Cependant,cen’estqu’en1981qu’unarticlepubliéparR.Fagindécrivitlaformenormaledomaine/clé (DK/NF). Cette dernière forme normale permet de garantirqu’unetableseratoujoursexempted’anomaliesdemodification.
Lesformesnormalessontimbriquéesdanslesensoùunetablevérifiantladeuxième forme normale (2NF) répond obligatoirement à la première(1NF).Demême, une table auniveau3NFest automatiquement conformeà 2NF, et ainsi de suite. Dans la plupart des applications pratiques, latroisièmeformenormaleestsuffisantepourassurerunhautdegréd’intégritéà la base de données. Pour avoir une certitude absolue, la formeDK/NFs’impose.
Unefoisquevousaureznormaliséunebaseautantqu’ilestpossible,vouspourrez procéder à des dénormalisations sélectives pour améliorer lesperformances. Faites alors attention aux types d’anomalies qui pourraientsurvenir.
PremièreformenormalePour respecter la première forme normale, une table doit satisfaire auxconditionssuivantes:
» Latableadeuxdimensions,avecdeslignesetdes
colonnes.
» Chaquelignecontientdesdonnéesquiserapportentà
unechoseouàuneportiond’unechose.
» Chaquecolonnecontientdesdonnéesquicorrespondent
àunseulattributdelachosedécrite.
» Chaquecellule(intersectiond’uneligneetd’unecolonne)
nedoitcontenirqu’uneseulevaleur.
» Lesentréesd’unecolonnedoiventtoutesêtredumême
type.Parexemple,sil’entréed’unelignedelacolonne
contientlenomd’unemployé,touteslesautreslignesdela
colonnedoiventcontenirlenomd’unemployé.
» Chaquecolonnedoitporterunnomunique.
» Deuxlignesnepeuventêtreidentiques(etdoncchaque
lignedoitêtreunique).
» L’ordredescolonnesetl’ordredeslignesn’ontaucune
signification.
Une table (ou relation) conforme à la première forme normale estimmuniséecontrecertainesanomaliesdemodificationmaispeutêtresujetteà d’autres. La table VENTES de la Figure 5.2 est en première forme
normale et souffre d’anomalies de suppression et d’insertion. Parconséquent,lapremièreformenormalepeutsuffireàcertainesapplications,maispasàd’autres.
DeuxièmeformenormalePour apprécier ce qu’est la deuxième forme normale, vous devezappréhender le concept de dépendance fonctionnelle. Une dépendancefonctionnelle est une relation entre attributs. Un attribut estfonctionnellement dépendant d’un autre si la valeur du second déterminecelle du premier. Si vous connaissez la valeur du second attribut, vouspouvezdoncdéterminercelledupremier.
Par exemple, supposons qu’une table dispose des attributs (colonnes)PRIX_STANDARD,NOMBRE_TESTSetPRIX_STANDARD_TOTALetqu’ilssontutilisésdansl’équationsuivante:
PRIX_STANDARD_TOTAL=PRIX_STANDARD*
NOMBRE_TESTS
PRIX_STANDARD_TOTALdépend fonctionnellement dePRIX_STAN-DARDetdeNOMBRE_TESTS.SivousconnaissezlesvaleursdePRIX_STANDARDetdeNOMBRE_TESTS,vouspouvezcalculerPRIX_STAN-DARD_TOTAL.
Toutetablequisetrouvedanslapremièreformenormaledoitavoirunecléprimaireunique.Cetteclépeutêtre forméeàpartird’uneoudeplusieurscolonnes.Unecléquiportesurplusd’unecolonneestditeclécomposite.Pourvérifierladeuxièmeformenormale(2NF),touteslescolonnesquineservent pas à composer la clé doivent dépendre de cette dernière.Ainsi,toute relation en 1NF, et dont la clé correspond à un unique attribut, estautomatiquement en 2NF. Si une relation est une clé composite, tous lesautresattributsdoiventdépendredeceuxquicomposentcetteclé.
En d’autres termes, si vous disposez d’une table dans laquelle certainsattributsneparticipantpasàlaclénedépendentpasdetouslescomposantsdeladiteclé,découpezcettetableendeuxpartiesouplus,etcejusqu’àcequetouslesattributs«nonclé»dechaquetabledépendentdeceuxquiencomposentlacléprimaire.
À ce stade, un exemple permettra d’y voir plus clair. Reprenons la tableVENTES de la Figure 5.2. Mais plutôt que d’enregistrer une seulecommandeparclient,vousajoutezunelignechaquefoisqueleclientachèteunarticlepourlapremièrefois.Deplus,certainsclients(dontCLIENT_IDestcomprisentre1001et1007)ontdroit àune réductionparticulière.LaFigure5.4reprendquelqueslignesdecettetable.
SurlaFigure5.4,CLIENT_IDn’identifiepasdemanièreuniqueuneligne(deuxlignescomportentlavaleur1001,etdansdeuxautreslignesilprendla valeur 1010). Cependant, la combinaison de CLIENT_ID et dePRODUIT identifie de manière unique une ligne. Les deux colonnesformentuneclécomposite.
FIGURE5.4DanslatableVENTES,lescolonnesCLIENT_IDetPRODUITconstituentuneclécomposite.
Sans le fait que certains clients obtiennent une réduction particulière, latableneseraitpasendeuxièmeformenormale.Eneffet,PRIX(unattributqui ne sert pas à former la clé) ne dépendrait que d’une partie de la clécomposite (PRODUIT). Du fait que certains clients ont droit à uneréduction, PRIX peut varier en fonction des valeurs des colonnesCLIENT_ID et PRODUIT. La table vérifie donc la deuxième formenormale.
TroisièmeformenormaleLes tablesde la deuxième formenormale sont toujours sujettes à certainstypesd’anomaliesdemodification.Cesanomaliessontengendréespardesdépendancestransitives.
Une dépendance transitive se produit quand un attribut dépend d’undeuxième attribut qui dépend à son tour d’un troisième. Supprimer deslignesdansunetablequipossèdecegenrededépendancepeutentraîneruneperted’informations.Unerelationquisetrouveentroisièmeformenormaleest une relation qui se trouve en deuxième forme normale et ne contientaucunedépendancetransitive.
Reprenonsla tableVENTESdelaFigure5.2.Voussavezdéjàqu’elleesten première forme normale. Tant que vous n’autorisez qu’une ligne parCLIENT_ID,votrecléprimairen’abesoinqued’unseulattribut,sibienquelatableestendeuxièmeformenormale.Cependant,latableesttoujourssujetteàdesanomalies.
Que se passe-t-il si le 1010 n’est pas satisfait de son détergent et qu’ildemandeàêtreremboursé?Vousdevrezsupprimerlatroisièmelignedelatable. Vous avez maintenant un problème, car vous allez aussi perdrel’information qui vous indique que le détergent vaut 4 euros. C’est unexemplededépendance transitive :PRIXdépenddePRODUIT, qui lui-mêmedépenddelacléprimaireCLIENT_ID.
Il vous faut découper la table VENTES en deux tables pour résoudre leproblème de la dépendance transitive. Sur la Figure 5.3, les deux tablesACHAT_CLIENT et PRIX_PRODUIT forment une base de données quivérifielatroisièmeformenormale.
Laformenormaledomaine/clé(DKNF)Une fois que vous avez passé une base de données en troisième formenormale,vousavezéliminépresque toutepossibilitédevoir surveniruneanomalie de modification (mais pas encore toutes les possibilités). Lesformes normales au-delà de la troisième sont définies pour éliminer lesquelques risques restants. La forme normale Boyce-Codd (BCNF), laquatrièmeformenormale(4NF)etlacinquièmeformenormale(5NF)sont
quelques-unes de ces formes supplémentaires. Chacune prévientl’apparitiond’anomaliesdemodificationdansuncasparticulier,maispasdans tous. Cela, seule la forme normale domaine/clé (DKNF) vous legarantit.
Unerelationestdansuneformenormaledomaine/clésichaquecontraintedelarelationestuneconséquencelogiquedeladéfinitiondesclésetdesdomaines.Dans ce schéma, une contrainte correspond à toute règle assezclairement énoncée pour que vous puissiez vérifier qu’elle s’applique ounon (en d’autres termes, si elle peut être évaluée comme étant vraie oufausse).Une clé est un identifiant unique pour les lignes de la table. Undomaineestunensembledevaleursautoriséespourunattribut.
Considérez encore une fois la base de données de la Figure 5.2, qui esten1NF.Quedevriez-vousfairepourlapasserenDKNF?
Table: VENTES(CLIENT_ID,PRODUIT,PRIX)
Clé: CLIENT_ID
Contraintes: 1.CLIENT_IDdéterminePRODUIT
2.PRODUITdéterminePRIX
3.CLIENT_IDdoitêtreunentier>1000
Pour renforcer la troisième contrainte, vous pouvezmodifier la définitiondudomainedeCLIENT_IDafind’yinclurecettecontrainte.CettedernièreestalorslaconséquencelogiquedeladéfinitiondudomainedelacolonneCLIENT_ID.PRODUITdépenddeCLIENT_IDetCLIENT_IDestuneclé,sibienque lacontrainte1estvérifiée,etestdesurcroîtuneconséquencelogiquedeladéfinitiondelaclé.Lacontrainte2poseunproblème.PRIXdépend de (est une conséquence logique de) PRODUIT qui n’est pas uneclé.Lasolutionconsisteàdiviser la tableVENTESendeuxtables.L’unede ces tables utilise CLIENT_ID pour clé tandis que l’autre prendPRODUIT pour clé. C’est la configuration de la Figure 5.3. La base dedonnéesquiyestreprésentée,enplusd’êtreen3NF,estaussiconformeauxspécificationsDKNF.
Concevezvosbasesdedonnéespourqu’ellessoientsipossibleenDKNF.Ilnepourraalorsplussurvenird’anomaliesdemodification.Silastructured’une base de données vous interdit de vous conformer à DKNF, vousdevrezintégrerdescontrôlesdecontraintesdansl’applicationquiutiliselabasededonnées.Eneffet,labasededonnéesnegarantitpasparelle-même
quecescontraintesserontrespectées.
LaformeanormaleAdopter une forme anormale est parfois une bonne solution. En effet, sivouspoussezlanormalisationtroploin,vousrisquezdegénérer tellementde tables que la base de données en deviendra totalement ingérable etinefficace. De plus, les performances pourraient s’effondrer au passage.Unestructureviableestsouventunpeudénormalisée.Enpratique,lesbasesdedonnéesnesontpresquejamais totalementenDKNF.Pourautant,vousdeveztenterdenormaliserlepluspossiblelesbasesdedonnéesquevousconcevezafind’élimineraumaximumlesrisquesdecorruptiondesdonnéesrésultantd’anomaliesdemodification.
Unefoislabasededonnéesnormaliséeautantquefairesepeut,revenezenarrière. Si les performances ne sont pas satisfaisantes, réexaminez votretravail de conception et voyez si une dénormalisation sélective serait àmême d’améliorer ces performances sans sacrifier l’intégrité. En ajoutantavec grand soin une certaine dose de redondance dans des emplacementsstratégiques, et en acceptant une part de dénormalisation, vous pourrezarriver à une base de données qui sera à la fois efficace et à l’abri desanomalies.
IIIEnregistreretextrairedesdonnées
DANSCETTEPARTIE...
Gérerdesdonnées.
Suivreletemps.
Traiterdesvaleurs.
Construiredesrequêtes.
VisiterlecontenuenlignedesNulssur
www.dummies.com/extras/sql.
L
Chapitre6Manipulerlesdonnéesd’unebase
DANSCECHAPITRE:
» Utiliserdesdonnées.
» Extraired’unetablelesdonnéesdontvousavezbesoin.
» N’afficherquelesinformationsvouluesàpartird’uneouplusieurstables.
» Mettreàjourdesinformationsdansdestablesetdesvues.
» Ajouterunenouvelleligneàunetable.
» Modifiertoutesoucertainesdesdonnéesd’uneligne.
» Supprimerunelignedansunetable.
es Chapitres 3 et 4 vous ont appris combien il est indispensable dedonner à votre base une bonne structure pour préserver l’intégrité desdonnéesqu’ellecontient.Maisplusquelastructure,cesontlesdonnées
qui vous intéressent. Vous voulez pouvoir les ajouter à des tables, lesextraireetlesafficher,lesmodifier,etenfinlessupprimer.
Enprincipe,lamanipulationdesdonnéescontenuesdansunebaseestassezsimple.Iln’estpascompliquédecomprendrecommentajouterdesdonnéesà une table – vous pouvez le faire ligne par ligne ou en une seule fois.Modifier,supprimerouextrairedeslignesd’unetablen’ariendedifficileenpratique.Enfait, lavéritabledifficultéestd’arriveràsélectionner leslignes que vous voulez modifier, extraire ou supprimer. Extraire desinformationspeutserévéleraussicompliquéquederechercheruneaiguilledansunemeuledefoin,car lesdonnéesquevousrecherchezpeuventêtrenoyéesdansunebaseextrêmementvolumineuse.Fortheureusement,etpourpeuquevoussachiezformulervotrerecherche,l’instructionSQLSELECT,l’ordinateurferatoutletravailàvotreplace.D’accord.Direqu’ilestfacile
de manipuler une base de données avec SQL, d’ajouter, de modifier, desupprimerouderetrouverdesinformationsestpeut-êtreunpeuexagéré...
Commençonsdoncparunexempleréellementsimple.
ExtrairedesdonnéesLamanipulation des données à laquelle les utilisateurs procèdent le plussouvent est l’extraction d’informations sélectionnées dans une base. Vousvoulez par exemple récupérer le contenu d’une certaine ligne parmi lesmilliers que comporte une table. Ou bien vous voulez trouver toutes leslignes qui satisfont un critère ou une combinaison de critères. Il se peutaussi que vous ayez besoin de récupérer toutes les lignes d’une table.L’instructionSELECTeffectuetoutescestâchesàvotreplace.
La forme la plus simple de l’instructionSELECT est celle qui retournetoutesleslignesd’unetable:
SELECT*FROMCLIENTS;
L’étoile(*)estuncaractèredesubstitution(unjoker)quidésignetout.Dansce contexte, l’étoile correspond à tous les noms de colonnes de la tableCLIENTS.Ilenrésultequetoutesleslignesdetouteslescolonnesdecettetable vous sont retournées. En d’autres termes, l’instruction ci-dessusrenvoielatotalitédelatable.
Les instructions SELECT peuvent être bien plus complexes que celleprésentéedansl’exempleprécédent.Enfait,certainesinstructionsSELECTsont si complexes qu’elles en sont virtuellement indéchiffrables. Cettecomplexitépotentielletientaufaitquevouspouvezaccolerdenombreusesclausesmodificatricesà l’instruction.LeChapitre10présentecesclausesdansledétail.JevaisicibrièvementparlerdelaclauseWHERE,quiestlaplus communément employée pour limiter le nombre de lignes retournéesparuneinstructionSELECT.
Une instruction SELECT accompagnée de la clause WHERE adopte laformesuivante:
SELECTliste_colonnesFROMnom_table
WHEREcondition;
Liste_colonnesspécifiequellescolonnesvousvoulezdanslatable.L’instructionn’afficheraquecescolonnes.LaclauseFROMindiquelatabled’oùvousvoulezextrairecescolonnes.LaclauseWHEREexcluttoutesleslignesquinerépondentpasàvosconditions.Uneconditionpeutêtresimple(par exemple, WHERE ETAT_CLIENT = ‘CA’) ou composée (parexemple WHERE ETAT_CLIENT = ‘CA’ AND STATUT =
‘Actif’). L’exemple suivantmontre à quoi peut ressembler une requêtequicomprenduneconditioncomposite:
SELECTNOM_CLIENT,TELEPHONE_CLIENTFROMCLIENTS
WHEREETAT_CLIENT=‘CA’
ANDSTATUT=‘Actif’;
SQLETLESOUTILSPROPRIÉTAIRES
LesinstructionsSELECTneconstituentpas leseulmoyend’extraire
desdonnéesd’unebase.SivousutilisezunSGBD,cedernierdispose
probablement d’outils propriétaires conçus pour cet usage. Vous
pouvezutilisercesoutils(quisontgénéralementassezintuitifs)pour
ajouter,supprimer,modifieretextrairedesdonnées.
De nombreux front-end de SGBD vous permettent de choisir entre
utilisercesoutilspropriétairesouutiliserSQL.Ilarriveparfoisqueles
outils propriétaires ne permettent pas d’obtenir tout ce qu’il est
possibled’exprimerenSQL.Sivousdevezeffectueruneopérationque
ces outils ne supportent pas, il vous faudra utiliser SQL. Il est donc
particulièrement utile de se familiariser avec ce langage, même si
vouscomptezutiliserunoutilpropriétaire laplupartdutemps.Pour
accompliravecsuccèsuneopérationtropcomplexepourvotreoutil
propriétaire, il faut que vous ayez les idées au clair sur le
fonctionnementdeSQLetsurcequ’ilestcapabledefaire.
L’instructionretournelesnomsetnumérosdetéléphonedetouslesclientsactifsquiviventenCalifornie.LemotcléANDsignifiequevousnevoulezrécupérerqueleslignesquivérifientlesdeuxconditionsquevousposez.
CréerdesvuesLa structure d’une base conçue en respectant les règles du genre (dontnotamment une normalisation appropriée, voir Chapitre 5) optimisel’intégritédesdonnées.Pourautant,cettestructuren’estsouventpaslaplusadaptée pour représenter visuellement les données qu’elle contient.Plusieursapplicationspeuventutiliserlesmêmesdonnées,maischacunelesafficheàsamanière.L’unedesfonctionnalités lespluspuissantesdeSQLest lapossibilitédegénérerdes représentationsdesdonnées– lesvues–dont lastructurediffèredecelledelabase.Les tablesdontvousutilisezles lignes et les colonnes dans une vue sont les tables de base. LeChapitre3traitedesvuesquisontundesélémentsdulangagededéfinitiondesdonnées(DDL).Danscettesection,j’expliqueàquoiserventlesvuesdanslecontextedelarécupérationetdelamanipulationdesdonnées.
UneinstructionSELECTretournetoujoursunrésultatsouslaformed’unetable virtuelle. Une vue est une variété de table virtuelle. Vous pouvezdifférencier une vue des autres variétés de tables virtuelles, car sadéfinitionestmémoriséedanslesmétadonnéesdelabase,cequiluiconfèreunepersistancequen’ontpaslesautrestablesvirtuelles.
Vouspouvezmanipulerunevuecommes’ils’agissaitd’unetablenormale.La différence est que les données d’une vue n’ont pas d’existenceindépendante. Elles proviennent en effet d’une ou plusieurs tables (cellesqui ont justement servi à définir la vue). Chaque application est donc àmêmed’appliquersonproprepointdevuesurunensemblededonnées.
Reprenons l’exemple de la base de données décrite auChapitre 5. Cettebasecontientcinqtables:CLIENTS,TESTS,EMPLOYES,COMMANDESetRESULTATS.SupposonsqueleresponsabledumarketingpourlesÉtats-UnisdésireconnaîtrelesÉtatsd’oùproviennentlescommandes.UnepartiedecetteinformationsetrouvedanslatableCLIENTSetuneautredanslatableCOMMANDES. Supposonsmaintenantque le responsabledu contrôlequalitédésirecomparer ladateà laquelleun testestcommandéetcelleà
laquellelerésultatfinalestproduit.Cettecomparaisonrequiertdesdonnéesdes tablesCOMMANDES etRESULTATS. Pour répondre aux besoins decesdeuxpersonnes,vouspouvezcréerdesvuesquicontiennentlesdonnéesdontvousavezbesoindanschaquecas.
ÀpartirdetablesPour le responsable du marketing, vous pouvez créer la vue représentéeFigure6.1.
FIGURE6.1LavueCOM-MANDES_PAR_ETATpourleresponsablemarketing.
L’instructionsuivantecréelavuesouhaitée:
CREATEVIEWCOMMANDES_PAR_ETAT
(NOM_CLIENT,ETAT,NUMERO_COMMANDE)
ASSELECTCLIENTS.NOM_CLIENT,ETAT,
NUMERO_COMMANDE
FROMCLIENTS,COMMANDES
WHERECLIENTS.NOM_CLIENT=
COMMANDES.NOM_CLIENT;
La nouvelle vue dispose de trois colonnes, NOM_CLIENT, ETAT etNUMERO_COMMANDE.NOM_CLIENTapparaît à la foisdansCLIENTSetdansCOMMANDES, et il sert de lien entre ces deux tables.La vue tirel’information ETAT de la table CLIENTS et l’information NU-MERO_COMMANDEdelatableCOMMANDES.
Dansl’exempleprécédent,vousdéclarezexplicitementlenomdescolonnesde la nouvelle vue. Cette précision n’est pas nécessaire si les noms descolonnesdelavuesontlesmêmesqueceuxdescolonnesauxquellesellescorrespondent dans les tables sources. L’exemple de la section suivanteprésente l’utilisation d’une instructionCREATEVIEWoù les noms descolonnessontfournisdemanièreimplicite.
AvecuncritèredesélectionLeresponsablequalitéabesoind’unevuedifférentedelaprécédente.ElleestdécriteFigure6.2.
FIGURE6.2LavueRAPPORT_RE-TARDpourleresponsablequalité.
L’instructionsuivantecréelavue:
CREATEVIEWRAPPORT_RETARD
ASSELECTCOMMANDES.NUMERO_COMMANDE,
DATE_COMMANDE,
DATE_RAPPORT
FROMCOMMANDES,RESULTATS
WHERECOMMANDES.NUMERO_COMMANDE=
RESULTATS.NUME-
RO_COMMANDE
ANDRESULTATS.PRELIMINAIRE_FINAL=‘F’;
Cette vue contient l’informationDATE_COMMANDEen provenance de latableCOMMANDES,et lesdatesdesrésultatsdéfinitifsfournisparlatableRESULTATS.SeulesleslignesdelatableRESULTATSdont lacolonnePRELIMINAIRE_FINALcontient la valeur « F » apparaissent dans lavue. Notez en passant que la liste des colonnes spécifiée dans la vueCOMMANDES_PAR_ETAT est facultative. La vue fonctionneraitparfaitementsanscetteliste.
AvecunattributmodifiéLa clause SELECT des deux exemples précédents ne contient que desnomsdecolonnes.Cependant,vouspouvezaussiyincluredesexpressions.SupposonsquelepropriétairedeVetLabfêtel’anniversairedesasociétéetdésirelecélébrerenoffrantuneréductionde10%àtoussesclients.Ilpeutcréer une vue basée sur les tablesTESTS etCOMMANDES en utilisantl’instructionsuivante:
CREATEVUE_ANNIVERSAIRE
(NOM_CLIENT,TEST,DATE_COMMANDE,
PRIX_ANNIVERSAIRE)
ASSELECTNOM_CLIENT,TEST_COMMANDE,
DATE_COMMANDE,
PRIX_STANDARD*.9
FROMCOMMANDES,TESTS
WHERETEST_COMMANDE=NOM_TEST;
LaFigure6.3montrecommentcréercettevue.
FIGURE6.3Lavuecrééepourafficherlesprixanniversaire.
Vous pouvez créer une vue à partir de plusieurs tables, comme dans lesexemples précédents, ou à partir d’une seule table. Si vous n’avez pasbesoin de certaines colonnes ou lignes d’une table, créez une vue qui lesélimine.Cela vous évitera demodifier accidentellement le contenu d’unecolonnesurlaquellevousnesouhaitezpastravailler.
Uneautrebonneraisondecréerdesvuesestd’assurerlasécuritédestablessous-jacentes. Si vous voulez permettre la consultation de quelquescolonnesd’une table toutendissimulant lesautres,vouspouvezcréerunevue ne contenant que les colonnes que vous souhaitez rendre publiques.Vous n’avez plus alors qu’à autoriser largement l’accès à la vue tout enrestreignantfortementl’accèsàlatablesous-jacente.C’estunbonprocédépourlasécuriser.LeChapitre14explorelasécuritédesbasesdedonnéesetexpliquecommentaccorderetrévoquerdesprivilèges.
ModifierlesvuesÀ peine créée, une table est en soi susceptible d’être remplie, éditée,modifiée, vidée... Les vues n’offrent pas nécessairement les mêmes
possibilités.Sivouséditezunevue,vousmodifiezenréalitélatablesous-jacente. Voici quelques problèmes potentiels que vous pouvez rencontrerlorsquevousactualisezdesvues:
» Certainesvuesprennentleursdonnéesdansplusieurs
tables.Sivousmodifiezunetellevue,commentsavoir
laquelledestablessous-jacentesseramodifiée?
» Unevuepeutinclureuneexpressiondansuneliste
SELECT.Dufaitquelesexpressionsnecorrespondentpas
directementàdeslignesdevostables,leSGBDnesaitpas
commentlesmettreàjour.
Supposonsquevousayezcrééunevueenutilisantl’instructionsuivante:
CREATEVIEWCOMP(NomEmploye,Paye)
ASSELECTNomEmploye,Salaire+CommASPaye
FROMEMPLOYES;
Pouvez-vousmettreàjourPayeenutilisantl’instructionsuivante?
UPDATECOMPSETPaye=Paye+100;
Celan’auraitaucunsenscarlatablesous-jacentenecontientpasdecolonnePaye. Vous ne pouvez pas mettre à jour quelque chose qui n’existe pasdanslatablesous-jacente.
Souvenez-vous de ceci chaque fois que vous utilisez une vue : vous nepouvezmodifierunecolonnedelavuequesiellecorrespondàunecolonned’unetabledebasesous-jacente.
AjouterdenouvellesdonnéesUnetablequivientd’êtrecréée(quecesoitàl’aided’uneinstructionSQLou via un RAD) est un ensemble structuré qui ne contient aucuneinformation.Unecoquillevide,donc.Pourlarendreutile,ilfautystockerdes données, dont vous disposez peut-être déjà (ou non) sous une forme
numérique. Ces données peuvent apparaître sous l’une des formessuivantes:
» Ellesnesontpasencorecompiléessousuneforme
numériquequelconque.Quelqu’undevraprobablement
utilisersonclavieretsonmoniteurpourlessaisir
manuellement,uneparune.Vouspourriezaussiutiliserun
scannerouunsystèmedereconnaissancevocale,maisce
typedesaisieestencorepeurépandu(etsurtoutd’une
fiabilitéinsuffisante).
» Ellesexistentdéjàsousuneformenumériquemais
dansunformatdifférentdeceluiutiliséparlestablesoù
vouscomptezlesstocker.Vousdevreztoutd’abordles
convertirdansleformatappropriépuislesinsérerdansla
base.
» Ellessontdéjàcompiléesdanslebonformat
numérique.Vousêtesprêtàopérerletransfertversune
nouvellebasededonnées.
Les sectionsqui suivent décrivent lesprocéduresd’insertiondesdonnéesdansunetableenfonctiondelaformequ’ellesprennent.Selonlecas,vouspourrez importer toutes vos données en une seule fois ou bienenregistrementparenregistrement.Chaqueenregistrementcorrespondàunelignedelatable.
AjouteruneligneàlafoisLaplupartdesSGBDpermettentde saisirdesdonnéesviaun formulaire.Cela vous permet de créer des écrans qui contiennent des champs pourchaque colonne d’une table. Le libellé des champs de saisie dans leformulaire renseigne l’utilisateur sur la colonne correspondante (si c’estécrit Date de commande, tout le monde est censé comprendre qu’il fautentrericiladatedelacommandeencoursdetraitement).L’opérateursaisitdansleformulairetouteslesdonnéesàenregistrerdansuneseuleetmême
ligne. Une fois que le SGBD a accepté cette nouvelle ligne, le systèmerafraîchit le formulaire pour permettre la saisie d’une nouvelle série dedonnées.Decettemanière,ilestsimple(quoiquefastidieux)deremplirlatableligneparligne.
Un système de formulaires est facile à comprendre et moins sujet auxerreursdesaisiequel’utilisationparexempledelistesdevaleursséparéespardesvirgules(formatcsv).Leprincipalproblème,cependant,estqu’iln’existe aucun standard en cedomaine.ChaqueSGBDpropose sa propresolutionpourcréerdesformulaires.Pourautant,cettediversiténeposepasdeproblèmeàl’opérateur,carlesformulairesadoptentpresquetoujourslemêmeaspectd’unSGBDàunautre.C’estledéveloppeurdel’applicationquidoitreprendresaformationàzérochaquefoisqu’ilchangedeSGBD,pas l’opérateur. Un autre problème possible tient au fait que certainesimplémentationsnepermettentpasdemettreenœuvredanslesformulairestous les contrôlesdevalidationquevous souhaiteriez effectuer lorsde lasaisiedesdonnées.
La meilleure solution pour maintenir l’intégrité des données de la baseconsisteenpremierlieuàlimiterlasaisiededonnéeserronées.Pourcela,vous devez appliquer des contraintes sur les champs de saisie d’unformulaire.Vousserezainsicertainque labasededonnéesn’acceptequedesvaleursdubontypeetquiappartiennentauxbonnesplagesdevaleurs.Bien entendu, ces contraintes nepeuvent pas permettre deprévenir toutesleserreurspossiblesetimaginables.
Sil’outildeconceptiondeformulairesdevotreSGBDnevouspermetpasd’appliquertouslescontrôlesrequispourpréserverl’intégritédesdonnées,vouspouvezcréervotrepropreécran,stockerlesdonnéessaisiesdansdesvariables,puistestercesvariablesenutilisantducodeapplicatif.Unefoisquevous serez certainque lesdonnées saisies sontvalides,vouspourrezinsérerlaligneenfaisantappelàlacommandeSQLINSERT.
Utilisez la commande SQLINSERTpour insérer les données dans uneligned’unetable:
INSERTINTOtable_1[(colonne_1,colonne_2,...,
co-
lonne_n)]
VALUES(valeur_1,valeur_2,...,valeur_n);
Commelelaissententendrelescrochets([]),lalistedesnomsdecolonnesestoptionnelle.Lalistepardéfautcorrespondàl’ensembledescolonnesdela table (dans l’ordre où elles sont définies dans celle-ci). Si vousfournissez lesvaleursdans l’ordredescolonnesde la table,cesélémentsseront enregistrés au bon endroit. Par contre, si les valeurs sont placéesdansunordredifférent, vousdevez explicitement indiquerquelle colonnedoitprendrequellevaleur.
UtilisezparexemplelasyntaxesuivantepoursaisirunenregistrementdanslatableCLIENTS:
INSERTINTOCLIENTS(CLIENT_ID,PRENOM,RUE,
VILLE,ETAT,
CODE_POSTAL,
TELEPHONE)
VALUES(:vclientid,‘David’,‘Taylor’,‘235
Nutley
Ave.’,
‘Nutley’,‘NJ’,‘07110’,‘(201)555-1963’);
LepremierélémentdelalisteVALUE,,vclientid,estunevariablequele codedevotreprogramme incrémente chaque foisquevousajoutezunenouvellelignedanslatable.Delasorte,vousêtescertainquedeuxlignesnecontiendrontpaslamêmevaleurCLIENT_ID.Cettecolonneesteneffetlacléprimairepourcettetable,etchaqueidentifiantdoitresterunique.Lesvaleurs restantes sont de simples données (plutôt que des variablescontenantcesdonnées).Bienentendu,vouspourriez,sivouslesouhaitiez,stocker toutes ces données dans des variables. Les arguments dumot cléVALUES peuvent en effet être aussi bien des variables que des copiesexplicitesdesdonnéeselles-mêmes.
AjouterdesdonnéesàdescolonneschoisiesVousvoulezparfoisnoter l’existenced’unobjet sanspourautantdisposerdetouteslesinformationsquileconcernent.Vouspouvezalorsinséreruneligne pour cet objet sans renseigner toutes les colonnes de la table. Pour
vousassurerquelatablesoitenpremièreformenormale,cependant,vousdevrez fournir suffisamment de données pour que toutes les lignes restentdistinctes(pourplusd’informationssurlapremièreformenormale,voirleChapitre5).Spécifierlacléprimairedelanouvellelignesuffitàsatisfairecettecondition.Lescolonnesquevousnerenseignerezpascontiendrontunevaleurnulle.
Voiciunexempledesaisiepartielle:
INSERTINTOCLIENTS(CLIENT_ID,PRENOM,NOM)
VALUES(:vclientid,‘Tyson’,‘Taylor’);
Vousn’insérezque lenumérod’identificationuniqueduclient,sonnometsonprénom.
AjouterunblocdelignesàunetableAlimenterunebasededonnéesligneparligneenutilisantdesinstructionsINSERT est particulièrement astreignant (et même carrément roboratif),surtoutsivousdevez lefaire toute la journée.Mêmelaplusélaboréedesinterfaces graphiques ne vous évitera pas de sombrer dans l’ennui.Clairement, ilest toujoursplusagréablededisposerd’unesolution fiablepermettant d’automatiser la saisie des données que d’obliger quelqu’un àresterassistoutelajournéedevantsonclavieretseslistingsdedonnées.
Automatiserlasaisieestpossiblequand,parexemple,lesdonnéesexistentdéjàsousuneformenumérique(quelqu’unlesadéjàsaisiesmanuellement).Inutilede fairebégayer l’histoire.Unordinateurest toutà fait capabledetransférer des données d’un fichier à un autre avec un minimumd’interventionhumaine.Pourpeuquevousconnaissiezlescaractéristiquesde ladonnée sourceet le formatde la tabledestination,vouspourrez (enprincipe)automatiserletransfert.
Copierdepuisunfichierdedonnéesétranger
Supposonsquevoussoyezentraindecréerunebasededonnéespourunenouvelleapplication.Certainesdesdonnéesdontvousavezbesoinexistentdéjàdansunfichier informatique. Ilpeuts’agird’unfichierplein texteoubiend’unetabledansunebasequegèreunautreSGBD.Cesdonnéessontpeut-être en ASCII ou en EBCDIC, ou dans n’importe quel formatpropriétaire.Commentprocéder?
Priez tout d’abord pour que les données soient dans un format largementutilisé.Sic’estlecas,ilsepeutqu’ilexisteunoutildeconversioncapabled’en réaliser la traduction dans un ou plusieurs autres formats courants.Votreenvironnementdedéveloppementsaitprobablementgérerl’undecesformats.Surlesordinateurspersonnels,Access,xBASEetMySQLsontlesplusutilisés.Silesdonnéesquevoussouhaitezutilisersontdansl’undecesformats,laconversionseraunjeud’enfant.Sinon,ilvousfaudraprocéderendeuxétapes.
En dernier ressort, vous pourrez toujours vous retourner vers desprofessionnelsdelaconversionsileformatdevosdonnéesesttropancien,propriétaire, autant dire défunt. Ces gens se sont spécialisés dans lesconversionset ils saventgérerdescentainesde formatsdontpersonneoupresquen’ajamaisentenduparler.Donnez-leurunebandeouundisquequicontientlesdonnéesàconvertir,et ilsvouslesrendrontdansleformatdevotrechoix.
TransférertoutesleslignesentredestablesImporterdesdonnéesdepuisunetabledevotrebasepourlescombinerauxdonnées d’une autre table est un problème bien moins délicat. Cetteimportationneposepasdedifficultéssilastructuredelasecondetableestidentique à celle de la première, c’est-à-dire si chaque colonne de lapremièretabledisposed’unecolonnecorrespondantedanslaseconde,etsiles typesdedonnéesdecesdeuxcolonnessontsinonidentiquesdumoinscompatibles.Sitelestlecas,vouspouvezcombinerlesdonnéesdesdeuxtables enutilisant l’opérateur relationnelUNION. Le résultat produit seraune table virtuelle qui sera la somme des deux tables. Je traite desopérateursrelationnels,dontUNION,auChapitre11.
Transférercertainescolonneset
certaineslignesentredestablesLa plupart du temps, les données de la table source n’adoptent pasexactementlastructuredelatableverslaquellevousvoulezlestransférer.Ilsepeutqueseulescertainescolonnesseretrouventdanslastructuredelatable destination, et ce sont précisément ces colonnes que vous vouleztransférer.EncombinantlesopérateursSELECTetUNION,ilestpossibledespécifierlescolonnesdelatablesourcequiserontinclusesdanslatablevirtuelle résultante.Enutilisant des clausesWHEREdans les instructionsSELECT, vous pouvez conditionner le transfert des lignes à certainesconditions.JetraitedansledétaildelaclauseWHEREauChapitre10.
Supposonsquevousdisposiezdedeux tables,PROSPECTSetCLIENTS,etquevousdésiriezconnaîtrelalistedespersonnesquiapparaissentdanslesdeuxtablescommerésidantdansleMaine.Vouspouvezcréerunetablevirtuelle contenant les informations voulues en utilisant la commandesuivante:
SELECTNOM,PRENOM
FROMPROSPECTS
WHEREETAT=‘ME’
UNION
SELECTNOM,PRENOM
FROMCLIENTS
WHEREETAT=‘ME’;
Voyonsceladeplusprès:
» LesinstructionsSELECTspécifientquelescolonnes
inclusesdanslatablevirtuellerésultatsontNOMet
PRENOM.
» LesclausesWHERElimitentleslignesinclusesàcelles
dontlacolonneETATcontientlavaleur‘ME’.
» LacolonneETATn’estpasinclusedanslatablede
résultat,maiselleestprésentedanslesdeuxtables
sources.
» L’opérateurUNIONcombinelesrésultatsproduitspar
SELECTsurPROSPECTSaveclesrésultatsproduitspar
SELECTsurCLIENTS,supprimeleslignesredondanteset
affichelerésultat.
Uneautremanièredecopierlesdonnéesd’unetableversuneautreconsisteàimbriqueruneinstructionSELECTdansune instructionINSERT.Cetteméthode(unesous-sélectionprésentéeauchapitre12)necréepasdetablevirtuelle mais duplique les données sélectionnées. Vous pouvez prendretoutes les lignes de la table CLIENTS et les insérer dans la tablePROSPECTS.Bienentendu,celanemarchequesi lesstructuresdesdeuxtables sont identiques. Si vous voulez par la suite placer dans la tablePROSPECTS les seuls clients qui vivent dans le Maine, une simpleinstructionSELECTcomportantuneseuleconditiondanslaclauseWHEREsuffiraàrépondreàlaquestion:
INSERTINTOPROSPECT
SELECT*FROMCLIENTS
WHEREETAT=‘ME’;
Bien que cette opération crée des données redondantes (vous stockezdésormaisdesdonnéesrelativesauxclientsdans la tablePROSPECTSetdans la table CLIENTS), il peut s’avérer utile de l’effectuer, car ellepermet d’améliorer les performances. Faites cependant attention à laredondance. Pour maintenir la cohérence des données, n’oubliez pas dereproduire dans la seconde table toutes les opérationsde suppression, demodification ou d’ajout auxquelles vous procédez dans la première. Unautreproblèmepotentielestlerisquededuplicationdesclésprimaires.Siunprospectpréexistantpossèdeunecléprimaire(ProspectID)identiqueà celle d’un client (ClientID) que vous tentez d’ajouter à la tablePROSPECTS,l’opérationd’insertionéchouera.
Modifierdesdonnéesexistantes
Dans cemonde, la seule chose permanente, c’est le changement. Si vouscraignez la routine, il vous suffit d’attendre un peu. Et puisque lechangementest la règle, ilenvademêmepourvosbasesdedonnées.Unclientchanged’adresse,lestockdiminue(cequiestheureuxpourvous),leclassement du championnat de foot évolue chaque semaine... Autantd’événementsquinécessitentuneactualisationdevotrebasededonnées.
L’instructionUPDATEdeSQLpermetdemodifierlesdonnéesd’unetable.À l’aide d’une seule instruction UPDATE, vous pouvez actualiser une,quelques-unesoutoutesleslignesd’unetable.Cetteinstructions’utilisedelamanièresuivante:
UPDATEnom_table
SETcolonne_1=expression_1,colonne_2=
expression_2,
...,colonne_n=expression_n
[WHEREpredicats];
LaclauseWHEREestfacultative.Ellesertàspécifierleslignesqu’ilfautmettreà jour.Sivousne l’utilisezpas, toutes les lignesde la tableserontmodifiées. La clause SET fournit les nouvelles valeurs à affecter auxcolonnesquevousmodifiez.
Prenezl’exempledelatableCLIENTSduTableau6.1.
TABLEAU6.1LatableCLIENTS
Nom Ville Indicatif Téléphone
Abe AbelsonSpringfield (714) 555-1111
BillBailey Decatur (714) 555-2222
ChuckWood Philo (714) 555-3333
DonStetson Philo (714) 555-4444
DolphStetson Philo (714) 555-5555
Lalistedesclientsestparfoismodifiée–lesgensdéménagent,changentdenuméro de téléphone, et ainsi de suite. Supposons qu’AbeAbelson quitteSpringfield pour habiter à Kankakee (c’est un joli nom, vous ne trouvezpas ?). Vous pouvez mettre à jour son enregistrement dans la table enutilisantl’instructionUPDATEsuivante:
UPDATECLIENTS
SETVILLE=‘Kankakee’,TELEPHONE=‘666-6666’
WHERENOM=‘AbeAbelson’;
Cetteinstructioncréelesmodificationsreprisesdansletableau6.2.
TABLEAU6.2LatableCLIENTSaprèsunUPDATEsuruneligne.
Nom Ville Indicatif Téléphone
AbeAbelson Kankakee (714) 555-1111
BillBailey Decatur (714) 555-2222
ChuckWood Philo (714) 555-3333
DonStetson Philo (714) 555-4444
DolphStetson Philo (714) 555-5555
Vous pouvez utiliser une instruction similaire pour modifier plusieurslignes. Supposons que la population de la localité Philo soit en traind’exploser.Ducoup,lavilleadésormaisbesoindesonproprecodelocal.VouspouvezappliquerunemodificationàtouslesclientsquiviventàPhiloàl’aided’uneseuleinstructionUPDATE:
UPDATECLIENTS
SETCODELOCAL=‘(619)’
WHEREVILLE=‘Philo’;
LatableressemblemaintenantàcellereprisedansleTableau6.3.
Ilestencoreplusfaciledemettreàjourenuneseulefoistoutesleslignesdela table.Nulbesoind’utiliser laclauseWHEREpour limiter leseffetsdel’instruction.Supposonsquelavillede
TABLEAU6.3LatableCLIENTSaprèsunUPDATEsurplusieurslignes.
Nom Ville Indicatif Téléphone
AbeAbelson Kankakee (714) 666-6666
BillBailey Decatur (714) 555-2222
ChuckWood Philo (619) 555-3333
DonStetson Philo (619) 555-4444
DolphStetson Philo (619) 555-5555
Rantoul acquière une importance politique majeure au point d’annexerKankakee,DecaturetPhilo,ainsiquetouteslesvillescitéesdanslabasededonnées.Vouspouvezmettreàjourtoutesleslignesdelamanièresuivante:
UPDATECIENTS
SETVILLE=‘Rantoul’;
LeTableau6.4vousmontrelerésultat.
TABLEAU6.4LatableCLIENTSaprèsUPDATEdetoutesleslignes.
Nom Ville Indicatif Téléphone
AbeAbelson Rantoul (714) 666-6666
BillBailey Rantoul (714) 555-2222
ChuckWood Rantoul (619) 555-3333
DonStetson Rantoul (619) 555-4444
DolphStetson Rantoul (619) 555-5555
La clauseWHERE que vous utilisez pour identifier les lignes auxquellesl’instruction UDPATE s’applique peut contenir une sous-sélection. Unesous-sélection vous permet demettre à jour des lignes dans une table enfonctionducontenud’uneautretable.
Supposonspar exemplequevous soyezungrossiste et quevotre basededonnéescontienneunebaseVENDEURSenregistrant lesnomsdetouslesproducteurs auxquels vous achetez vos produits. Vous pouvez aussi avoirunetablePRODUITSpourlesnomsdetouslesproduitsquevousrevendezet les prix de chacun. La tableVENDEURS possède les colonnesVEN-DEUR_ID,VENDEUR_NOM,RUE,VILLE,ETATetCODE_POSTAL.Latable PRODUITS contient PRODUIT_ID, PRODUIT_NOM,
VENDEUR_IDetPRIX_VENTE.
L’un de vos vendeurs,CumulonimbusCorporation, décide d’augmenter leprixdetoussesproduitsde10%.Pourmaintenirvotremarge,vousdevezremonter les prix auxquels vous vendez les produits de Cumulonimbusde10%.VouspouvezlefaireenuneseuleinstructionUPDATE:
UPDATEPRODUITS
SETPRIX_VENTE=(PRIX_VENTE*1.1)
WHEREVENDEUR_IDIN
(SELECTVENDEUR_IDFROMVENDEURS
WHEREVENDEUR_NOM=‘Cumulonimbus
Corporation’);
Lasous-sélectiontrouveleVENDEUR_IDdeCumulonimbus.Vouspouvezalors utiliser le champ VENDEUR_ID de la table PRODUITS pourrecherchertoutesleslignesquevousdevezmettreàjour.LesprixdetouslesarticlesdeCumulonimbusserontaugmentésde10%.Lesautrestarifsneseront pas modifiés. Je traite des sous-sélections plus en détail auChapitre12.
Transférerdesdonnées
En plus d’INSERT et UPDATE, vous disposez d’une instructionsupplémentairepourajouterdesdonnéesàunetableouàunevue:MERGE.Ellepermetdefusionnerdesdonnéesàpartird’unetableoud’unevueversuneautretableouvue.L’objectifpeutêtred’ajouterdenouvelleslignesoud’effectuer une mise à jour. MERGE est intéressante pour prendre desdonnéesquiexistentdéjàdansunebasepourlescopierversunenouvelledestination.
PrenonscommeexemplelabasededonnéesVetLabdécriteauChapitre5.Supposons que, dans le personnel du laboratoire, se trouvent descommerciaux chargés des ventes, d’autres qui ont simplement à traitercelles-ci, ainsi que des employés des services généraux. Les affaires devotre filiale américaineont été bonnes l’annéedernière, et vousvoudriezpartager les fruits de la croissance avec votre personnel. Vous décidezd’attribuer une prime de 100 euros aux commerciaux qui ont réalisé aumoinsunevente,etde50eurosàtouslesautres.Vouscommencezparcréerune table PRIMES.Vous y insérez ensuite un enregistrement pour chaqueemployé qui apparaît aumoins une fois dans la tableCOMMANDES, enleuraffectantuneprimepardéfautde100euros.
Vous voulez maintenant utiliser l’instruction MERGE pour insérer denouveaux enregistrements concernant les autres employés. Le montant deleurprimeestdoncde50euros.VoyonslecodequipermetdecréerlatablePRIMESetdelaremplir:
CREATETABLEPRIMES(
NOM_EMPLOYECHARACTER(30)PRIMARYKEY,
PRIMENUMERICDEFAULT100);
INSERTINTOPRIMES(NOM_EMPLOYE)
(SELECTNOM_EMPLOYEFROMEMPLOYES,COMMANDES
WHEREEMPLOYES.NOM_EMPLOYE=
COMMANDES.COMMERCIAL
GROUPBYEMPLOYES.NOM_EMPLOYE);
Vous pouvezmaintenant interroger la table PRIMES pour voir ce qu’ellecontient:
SELECT*FROMPRIMES;
NOM_EMPLOYEPRIME
-------------------------
BrynnaJones100
ChrisBancroft100
GregBosser100
KyleWeeks100
Ilestensuitefacilededonneruneprimede50eurosaurestedesemployés:
MERGEINTOPRIMES
USINGEMPLOYES
ON(PRIMES.NOM_EMPLOYE=
EMPLOYES.NOM_EMPLOYE)
WHENNOTMATCHEDTHENINSERT
(PRIMES.NOM_EMPLOYE,PRIMES.PRIME)
VALUES(EMPLOYES.NOM_EMPLOYE,50);
Vous insérez ainsi dans la table PRIMES des enregistrements pour lespersonnesde la tableEMPLOYESqui ne sont pasdéjàmémoriséesdansladitetablePRIMES.Cesagentssevoientattribueruneprimede50euros.UnerequêtesurlatablePRIMESpourraitalorsdonnerceci:
SELECT*FROMPRIMES;
NOM_EMPLOYEPRIME
-------------------------
BrynnaJones100
ChrisBancroft100
GregBosser100
KyleWeeks100
NethDoze50
MattBak50
SamSaylor50
NicFoster50
Lesquatrepremiersenregistrements,ceuxquiontétécréésparl’instructionINSERT, sont classés dans l’ordre alphabétique des noms. Les quatreautres, ajoutés via l’instructionMERGE, apparaissent dans l’ordre où ilsfigurentdanslatableEMPLOYES.
SupprimerdesdonnéesobsolètesLetempspasse,etvotretablepeutfinirparcontenirdesdonnéesquinesontplusutiles.Vousvoudrezalorslessupprimer,carellesoccupentdelaplaceetprêtent à confusion.Vouspourriez les transférerdansune table archiveque vous rendriez inaccessible. De la sorte, vous pourrez toujours lesrécupérersilebesoins’enfaitsentir.Maisquevousdécidiezd’archiverounondes données obsolètes, il faudra les supprimer de la base. SQLvouspermetd’effacerdeslignesdevostablesàl’aidedel’instructionDELETE.
Vous pouvez détruire toutes les lignes d’une table en utilisant une seuleinstructionDELETE,oulimiterlasuppressionàquelqueslignesenajoutantuneclauseWHERE.Lasyntaxequevousemploierezest semblableàcelledel’instructionSELECT,àceciprèsquevousnespécifiezaucunecolonne.Si vous supprimez une ligne, vous supprimez à l’évidence toutes lesdonnéesquecontiennentsescolonnes!
Par exemple, supposons que votre client David Taylor vienne juste dedéménageràTahiti,sibienqu’ilnevaplusjamaisvousacheterquoiquecesoit.VouspouvezleretirerdevotretableCLIENTSenutilisantl’instructionsuivante:
DELETEFROMCLIENTS
WHEREPRENOM=‘David’ANDNOM=‘Taylor’;
Ensupposantqu’iln’existequ’unseulclientDavidTaylor,cetteinstructioneffectuera la suppression attendue. Si vous avez deux clients qui senommentDavidTaylor,vousdevrezajouteruneclauseWHERE (tellequeRUEouTELEPHONE,ouCLIENT_ID)pourêtrebiencertainquevoussupprimezlebonclient.Sinon,touslesDavidTaylordevotretableseronteffacés,ycomprisceuxquinesontpaspartisàTahiti...
A
Chapitre7Gérerl’historiquedesdonnées
DANSCECHAPITRE:
» Définirdespériodes.
» Suivreàlatracecequisepasseàcertainsinstants.
» Fournirunhistoriquedesmodificationsapportéesauxdonnées.
» Savoircequis’estpasséetquandl’évènementaétéenregistré.
vant SQL:2011, le standard SQL de l’ISO/IEC ne disposait d’aucunmécanismepourgérerlesdonnéesquiétaientvalidesàuninstantdonnémaisinvalidesàunautre.Or,touteapplicationquiabesoindesuivreà
la trace l’étatdesdonnéesabesoindecette fonctionnalité.Cela signifiaitdoncquelachargedeconserverunetracedecequiétaitvalideàuninstantdonnéretombaitsurleprogrammeurdel’applicationplutôtquesurlabasede données. Autant dire que c’était la porte ouverte à des applicationscompliquées,horsbudget,enretardetinfestéesdebogues.
UnenouvellesyntaxeaétéajoutéedansSQL:2011pourpermettredegérerdesdonnées temporellessansavoirà intervenirdans lecodequigère lesdonnées sans tenir compte de la temporalité.C’est ungros avantagepourquiconque souhaite qu’une base de données SQL intègre la gestion destemporalités.
Qu’est-ce que j’entends par données temporelles ? LE standardSQL:2011del’ISO/IECn’utilisepasceterme,maisilestfréquentdanslacommunautédesbasesdedonnées.DansSQL:2011,unedonnéetemporelleest une donnée à laquelle une ou plusieurs périodes de temps sontassociées,durantlesquellesladonnéeestcenséeêtrevalide.Autrementdit,cela signifie qu’avec les données temporelles, vous pouvez déterminer siunecertainedonnéeestvalideounon.
Danscechapitre,jevousprésenteleconceptdepériode,enledéfinissantd’une manière bien particulière. Vous découvrirez ensuite les différentestemporalités et les effets qu’elles peuvent avoir sur la définition de clésprimairesetdecontraintesd’intégritéréférentielle.Pourfinir,jeprésentelamanièredontdesdonnées trèscomplexespeuventêtrestockéeset traitéesdansdestablesbitemporelles.
ComprendrelespériodesdansSQL:2011
Quoique les versions du standard SQL antérieures à SQL:2011comportaient les types de données TIME, TIMESTAMP, et INTERVAL,aucuntypededonnéesnerecouvraitlanotiondepériodecommençantàuncertain instantetse terminantàunautre.Unenouvellemanièred’adresserce besoin est de définir un type de données PERIOD. Toutefois,SQL:2011neprocèdepasainsi.IntroduireunnouveautypededonnéesdansSQLàcetteétape tardivedesondéveloppement,c’étaitprendre le risquede remettre en cause l’écosystème qui s’était développé autour. Il auraitfalludes interventionschirurgicales très lourdesdans tous lesproduitsdebasesdedonnéesdumarchépourajouterunnouveautypededonnées.
En conséquence, plutôt que d’ajouter un type de données PERIOD,SQL:2011résoutleproblèmeenajoutantdesdéfinitionsdepériodes sousla forme de métadonnées aux tables. Une définition de période est unélémentnomméd’unetable,quiidentifieunepairedecolonnescontenantlemoment initial et lemoment final. Les commandesCREATETABLE etALTERTABLEutiliséspourcréeretmodifierdestablesontétémisesàjourpoursupporterunenouvellesyntaxepermettantdecréeroudétruiredetellespériodes.
Unepériodeestdéterminéepardeuxcolonnes:unecolonnededébutetunecolonne de fin. Ces colonnes sont conventionnelles, tout comme lescolonnes de n’importe quel type de données temporel. Chacune porte unnom unique. Commementionné plus tôt, une définition de période est unélémentnomméd’une table.Elle se trouvedans lemêmeespacedenomsquelesnomsdescolonnes,sibienqu’ellenedoitpasporterlenomd’unecolonne.
SQLsuitunmodèlefermé-ouvertpourlespériodes,cequisignifiequ’unepériodecomprendundébutmaispasdefin.Pourtoutelignedelatable,lafind’unepériodedoitêtresupérieureàsondébut.C’estunecontraintedontleSGBDassurelerespect.
Deux dimensions du temps sont à prendre en compte lorsque vousmanipulezdesdonnéestemporelles:
» Letemps-valideestlapériodedurantlaquelleuneligne
delatablereflètebienlaréalité.
» Letemps-transactionestlapériodedurantlaquellela
ligneestenregistréedanslabasededonnées.
Le temps-valide et le temps-transaction d’une ligne de la table n’ont pasbesoin d’être identiques. Par exemple, dans une base de données quienregistreladuréedevaliditéd’uncontrat,l’informationsurlecontratpeutêtre insérée avant que le contrat ne prenne effet (ce qui se fait d’ailleursgénéralement).
Dans SQL:2011, des tables distinctes peuvent être créées et maintenuespour les deux types de temporalités, à moins d’utiliser une tablebitemporelle (il en sera question plus loin dans ce chapitre). Lesinformations du temps-transaction sont conservées dans des tables quicontiennent une période temps-système, signalée par le mot-cléSYSTEM_TIME. Quant aux informations du temps-valide, elles sontmaintenues dans des tables qui contiennent une période de temps-application. Vous pouvez donner n’importe quel nom à une période detemps-application,pourvuquelenomnesoitpasdéjàutiliséailleurs.Vousavezledroitdedéfinirauplusunepériodedetemps-systèmeetunepériodedetemps-application.
QuoiquelagestiondesdonnéestemporellesdansSQLaétéintroduitepourla première fois avec SQL:2011, les gens n’ont pas attendu qu’elle soitintégrée aux produits de bases de données pour se servir de donnéestemporelles.Onutilisaitclassiquementdeuxtables,unepourledébutetuneautrepour la finde lapériode.Le faitqueSQL:2011n’introduisepasdetype de donnéesPERIOD,mais plutôt des définitions de période sous laformedemétadonnées,signifiequelestablesutiliséesjusqu’alorspeuventfacilementêtrerenduescompatiblesaveclenouveaumécanisme.Lalogique
quipermetdefournirdesinformationssurunepériodepeutêtreretiréedesapplications, ce qui permet de les simplifier, d’en améliorer lesperformancesetd’enrenforcerlafiabilité.
Travailleravecdestablesdepériodesdetemps-application
Prenonsunexempleutilisantdes tablesdepériodesde temps-application.Considérons une entreprise qui veut conserver la trace temporelle desdépartements par lesquels sont passés les employés durant leur contrat.L’entreprise peut y parvenir en créant des tables de périodes de temps-applicationpourlesemployésetlesdépartements,delamanièresuivante:
CREATETABLEemploye_atpt(
EmpIDINTEGER,
EmpDebutDATE,
EmpFinDATE,
EmpDeptVARCHAR(30),
PERIODFOREmpPeriode(EmpDebut,EmpFin)
);
Ladateetl’heurededébut(EmpDebutdanscetexemple)figurentdanslapériode,maiscellesdefin (EmpFindanscetexemple)n’yfigurentpas.C’estcela,lasémantiquefermé-ouvert.
Jen’aipasencoreprécisédecléprimaire,carc’estunpeupluscomplexelorsquevoustraitezdesdonnéesclassiques.Jevaisenparleràlafindecechapitre.
Pourl’heure,insérezquelquesdonnéesdanslatablepourvoiràquoicelaressemble:
INSERTINTOemploye_atpt
VALUES(12345,DATE‘2011-01-01’,DATE‘9999-12-
31’,
‘Ventes’);
Latablequienrésulteestreprésentéedansletableau7.1.
TABLEAU7.1Unetableàpériodedetemps-applicationnecontenantqu’uneligne
EmpID EmpDebut EmpFin EmpDpt
12345 2011-01-01 9999-12-31 Ventes
Ladatede fin9999-12-31 indiqueque le contrat de travail de l’employédans l’entreprise ne s’est pas encore terminé. Pour plus de simplicité, jen’aipasfaitfigurerlesheures,lesminutesetlessecondes,etencoremoinslesfractionsdesecondedesexemples.
Supposons maintenant que, le 15 mars 2012, l’employé 12345 esttemporairementaffectéaudépartementIngénieriejusqu’au15juillet2012,date à laquelle il retournera au département Ventes. Vous pouvez lementionnerenutilisantlacommandeUPDATEsuivante:
UPDATEemploye_atpt
FORPORTIONOFEmpPeriode
FROMDATE‘2012-03-15’
TODATE‘2012-07-15’
SETEmpDept=‘Ingénierie’
WHEREEmpID=12345;
Après la mise à jour, la table contient trois lignes, comme dans letableau7.2:
TABLEAU7.2Latabledepériodesdetemps-applicationaprèsmiseàjour.
EmpID EmpDebut EmpFin EmpDpt
12345 2011-01-01 2012-03-15 Ventes
12345 2012-03-15 2012-07-15 Igénierie
12345 2012-07-15 9999-12-31 Ventes
En supposant que l’employé 12345 travaille toujours au départementVentes,latablerendcomptefidèlementdesonappartenancedepuislejourdel’an2011jusqu’àl’instantprésent.
Sivouspouvezinsérerdenouvellesdonnéesdanslatableetmettreàjourdesdonnéesquiyfigurent,vousdevriezpouvoirensupprimerdesdonnées.Toutefois, supprimer des données d’une table de périodes de temps-application peut s’avérer un peu plus complexe que supprimer des lignesdans une table normale, c’est-à-dire non temporelle. Par exemple,supposonsquel’employé12345,plutôtqued’êtretransféréaudépartementIngénierie le 15 mars 2012, quitte l’entreprise et soit réembauchéle15juilletsuivant.Àlabase,latabledespériodesdetemps-applicationnecontiendraqu’uneligne,commedansletableau7.3.
TABLEAU7.3Latabledepériodesdetemps-applicationavantunemiseàjourouune
suppression.
EmpID EmpDebut EmpFin EmpDpt
12345 2011-01-01 9999-12-31 Ventes
UnecommandeDELETEvamettreàjourlatablepourindiquerlapériodedurantlaquellel’employé12345estparti:
DELETEemploye_atpt
FORPORTIONOFEmpPeriode
FROMDATE‘2012-03-15’
TODATE‘2012-07-15’
WHEREEmpID=12345;
Latablequienrésulteestreprisedansletableau7.4.
TABLEAU7.4Latabledepériodesdetemps-applicationavantaprèsunesuppression.
EmpID EmpDebut EmpFin EmpDpt
12345 2011-01-01 2012-03-15 Ventes
12345 2012-07-15 9999-12-31 Ventes
La table reflète mentionne maintenant les périodes durant lesquellesl’employé12345aétéeffectivementemployéparl’entreprise,sibienqu’onnoteunvidedurantlapériodeoùill’avaitquittée.
Vousaureznotéquelquechosed’intriguantaveclestablesprésentéesdanscettesection.Danslelistingd’unetablenontemporelledesemployésd’uneentreprise, le numéro d’identifiant d’un employé suffit pour servir de cléprimaire,carilidentifiedemanièreuniqueunemployé.Toutefois,unetablede périodes de temps-application peut contenir plusieurs lignes pour unmême employé. En conséquence, l’identifiant d’un employé ne peut plusêtre utilisé commeclé primaire.Lesdonnées temporelles doivent lui êtreassociées.
Concevoirdesclésprimairesdansunetabledepériodesdetemps-applicationDans les tables 7.2 et 7.4, il est clair que l’identifiant de l’employé(EmpID)nepeutpasgarantir l’unicité.Eneffet,onpeut trouverplusieurslignesaveclemêmeEmpID.Pourgarantirqu’aucunelignen’estdupliquée,le début (EmpDebut) et la fin (EmpFin) de la période doivent figurerdanslacléprimaire.Toutefois,ilnesuffitpasdelesyinclure.Jetezunœilsurletableau7.5,quiprésenteuncasoùl’employé12345aététransféréaudépartement Ingénierie durant quelques mois, avant de rejoindre sondépartementd’origine.
TABLEAU7.5Unesituationquevoussouhaiterezéviter.
EmpID EmpDebut EmpFin EmpDpt
1245 2011-01-01 9999-12-31 Ventes
1245 2012-03-15 2012-07-15 Ingénierie
Lesdeuxlignesdela tablesontgarantiesd’êtreuniquesdufaitquelacléprimairecomprendEmpDebutetEmpFin,maisnotezquelesdeuxpériodesse chevauchent. Il semble que l’employé 12345 fasse partie des deuxdépartementsVentesetIngénieriedu15mars2012au15juillet2012.Dansquelques entreprises, cela peut être possible, mais cela ajoute à lacomplexitéetpeutcorromprelesdonnées.Danslaplupartdesentreprises,onveillera au respectd’une contrainte imposantqu’unemployénepuissefaire partie que d’undépartement à la fois.Vous pouvez ajouter une tellecontrainte à la table avec une commande ALTER TABLE telle que lasuivante:
ALTERTABLEemploye_atpt
ADDPRIMARYKEY(EmpID,EmpPeriodeWITHOUT
OVERLAPS);
Ilexisteunemeilleuremanièredeparveniraurésultatquedecréerlatableavantd’yajouterlacontraintedecléprimaire.Eneffet,vouspouvezinclurela contrainte de clé primaire dans l’instruction CREATE initiale. Celapourraitressemblerà:
CREATETABLEemploye_atpt
EmpIDINTEGERNOTNULL,
EmpDebutDATENOTNULL,
EmpFinDATENOTNULL,
EmpDeptVARCHAR(30),
PERIODFOREmpPeriode(EmpDebut,
EmpFin)
PRIMARYKEY(EmpID,EmpPeriodeWITHOUT
OVER-
LAPS)
);
Dorénavant,leslignesdontlespériodessechevauchentsontinterdites.Tantquej’yétais,j’aiajoutédescontraintesNOTNULLàtouslesélémentsdelacléprimaire.Unevaleurnulleaffectéeàl’unquelconquedeceschampsseraunesourced’erreursmaintenant.Normalement, leSGBDdevraits’enoccuper,maispourquoiprendrelerisque?
Appliquerdescontraintesréférentiellesàunetabledepériodesdetemps-applicationToute base de données censée contenir plus qu’une simple liste vaprobablementrequérirplusd’unetable.Sitelestlecas,lesrelationsentrelestablesdoiventêtredéfinies,etdescontraintesd’intégritéréférentiellesmisesenplace.
Dans l’exemplede ce chapitre, vousdisposezd’une tabledepériodesdetemps-application.Ilexisteunerelationd’unàplusieursentrelatabledesdépartementsetlatabledesemployés,carundépartementpeutcomprendreplusieurs employés, mais un employé ne peut appartenir qu’à un seuldépartement.Cela signifie que vous devez rajouter une clé étrangère à latable des employés, qui référence la clé primaire de la table desdépartements.Ceciàl’esprit,créezdenouveaulatabledesemployés,cettefoisenutilisantunecommandeCREATEpluscomplexe.Créezlatabledesdépartementsdelamêmemanière.
CREATETABLEemploye_atpt(
EmpIDINTEGERNOTNULL,
EmpDebutDATENOTNULL,
EmpFinDATENOTNULL,
EmpNomVARACHAR(30),
EmpDeptVARCHAR(30),
PERIODFOREmpPeriode(EmpDebut,EmpFin)
PRIMARYKEY(EmpID,EmpPeriodeWITHOUTOVERLAPS)
FOREIGNKEY(EmpDept,PERIODEmpPeriode)
REFERENCESdept_atpt(DeptID,PERIODDeptPeriode)
);
CREATETABLEdept_atpt(
DeptIDVARCHAR(30)NOTNULL,
ManagerVARCHAR(40)NOTNULL,
DeptDebutDATENOTNULL,
DeptFinDATENOTNULL,
PERIODFORDeptDuree(DeptDebut,DeptFin),
PRIMARYKEY(DeptID,DeptDureeWITHOUTOVERLAPS)
);
Fairedesrequêtessurunetabledepériodesdetemps-applicationMaintenant,desinformationsdétailléespeuventêtreextraitesdelabasededonnéesenutilisantdescommandesSELECTquiexploitentlespériodes.
Parexemple,vouspourriezsouhaiterrécupérerlalistedetouslesemployésquitravaillentactuellementdansl’entreprise.AvantSQL:2011,vousdeviezécrireunecommanderessemblantàcela:
SELECT*
FROMemploye_atpt
WHEREEmpDebut<=CURRENT_DATE()
ANDEmpFin>CURRENT_DATE();
Avec la nouvelle syntaxe, vous pouvez obtenir le même résultat plusfacilement,commesuit:
SELECT*
FROMemploye_atpt
WHEREEmpPeriodeCONTAINSCURRENT_DATE();
Vous pouvez aussi récupérer la liste des employés qui ont travaillé dansl’entreprisesurunepériodedonnée,commesuit:
SELECT*
FROMemploye_atpt
WHEREEmpPeriodeOVERLAPS
PERIOD(DATE(‘2012-01-01’),DATE(‘2012-09-
16’));
Hormis CONTAINS et OVERLAPS, vous pouvez utiliser d’autresprédicats comme EQUALS, PRECEDES, SUCCEEDS, IMMEDIATLYPRECEDES,etIMMEDIATLYSUCCEEDS.
Cesprédicatsfonctionnentainsi:
» SiunepériodeEQUALSuneautre,alorsellessont
strictementidentiques.
» SiunepériodePRECEEDSuneautre,alorsellesedéroule
avant.
» SiunepériodeSUCCEEDSuneautre,alorsellesedéroule
après.
» SiunepériodeIMMEDIATLYPRECEEDSuneautre,alors
ellesedéroulejusteavantetyestcontigüe.
» SiunepériodeIMMEDIATLYSUCCEEDSuneautre,alors
ellesedéroulejusteaprèsetyestcontiguë.
Travailleravecdestablesdeversionssystèmes
Lestablesdeversionssystèmesserventàd’autresusagesquelestablesdepériodes de temps-application, et fonctionnent en conséquencedifféremment.Lestablesdepériodesdetemps-applicationvouspermettentde définir des périodes et de traiter les données associées à un instantdonné. Les tables de versions systèmes sont conçues pour créer unhistoriquedel’ajout,delamodificationoudelasuppressiondedonnéesdelabasededonnées.Parexemple,ilestimportantpourunebanquedesavoirexactementquandunretraitouundépôtaétéeffectué,etcetteinformationdoitêtreconservéedurantuncertaintempsprévuparlaloi.Demême,destraders ont besoin de conserver la trace de la date de leurs achats et deleurs ventes. On trouve bien d’autres cas à citer, où il est important deconserverlatraced’unévénement,àlafractiondesecondeprès.
Les applications telles que les logiciels de banque ou de trading ont desexigencesstrictes:
» Touteopérationdemiseàjouroudesuppressiondoit
sauvegarderl’étatoriginaldelaligneavantdelemodifier.
» Lesystème,plutôtquelesutilisateurs,maintientledébut
etlafindespériodesdansleslignes.
Leslignesquiontfaitl’objetd’unemiseàjouroud’une
suppressionrestentdanslatableetsontdèslorsqualifiées
deligneshistoriques.Lesutilisateursnepeuventpas
modifierlecontenudeceslignesoulespériodesquileur
sontassociées.Seullesystèmelepeut.Illefaitlorsd’une
miseàjourdecolonnesquinecorrespondentpasàdes
périodesdanslatable,oulorsqu’uneligneestsupprimée.
Cescontraintesgarantissentquel’historiquedesdonnées
nepeutêtrealtéré,cequipermetderépondreaux
exigencesdesauditeursetauxrèglesdesautoritésde
régulation.
Les tables de versions systèmes se distinguent des tables de périodes detemps-application sur plusieurs points dans la commande CREATE quipermetdecréerlesunesetlesautres:
» Alorsdansunetabledepériodesdetemps-application,
l’utilisateurpeutnommerlapériodecommeill’entend,elle
doitêtretoujoursnomméeSYSTEM_TIMEdansunetable
deversionssystèmes.
» LacommandeCREATEdoitcomprendrelesmots-clés
WITHSYSTEMVERSIONING.QuoiqueSQL:2011permette
queletypededonnéesdudébutetdelafindelapériode
soitdutypeDATEoudutypeTIMESTAMP,vouspréférez
toujoursutiliserTIMESTAMP,carcelavousprocurebien
plusdeprécisionquecelledujour.Bienentendu,letype
adoptépourledébutd’unepériodedoitêtreidentiqueà
celuidelafin.
Pourillustrerl’utilisationdestablesdeversionssystèmes,jevaisprolongerl’exempledesemployésetdesdépartements.Vouspouvezcréerune tabledeversionssystèmesaveclecodesuivant:
CREATETABLEemploye_sys(
EmpIDINTEGER,
Sys_DebutTIMESTAMP(12)GENERATEDALWAYSASROW
START,
Sys_FinTIMESTAMP(12)GENERATEDALWAYSASROW
END,
EmpNomVARCHAR(30),
PERIODFORSYSTEM_TIME(SysDebut,SysFin)
)WITHSYSTEMVERSIONING;
Unelignedansunetabledeversionssystèmesestconsidéréeêtreunelignecourante du système si sa période de temps-système comprend l’instantprésent.Autrement,elleestconsidéréecommeunelignehistorique.
Lestablesdeversionssystèmessonttrèssemblablesauxtablesdepériodesde temps-application sur de nombreux points, mais elles en différent surd’autres.Enparticulier:
» Lesutilisateursnepeuventaffecteroumodifierlesvaleurs
descolonnesSys_DebutetSys_Fin.Cesvaleurssont
affectéesetmodifiéesautomatiquementparleSGBD.
Cettesituationestimposéeparlesmots-clésGENERATED
ALWAYS.
» LorsquevousutilisezlacommandeINSERTpourajouter
quelquechosedansunetabledeversionssystèmes,la
valeurdelacolonneSys_Debutprendautomatiquement
pourvaleurl’instantdelatransaction.Lavaleuraffectéeà
lacolonneSys_Finestlaplusgrandevaleurdutypede
donnéesdecettecolonne.
» Danslestablesdeversionssystèmes,lescommandes
UPDATEetDELETEagissentsurleslignescourantes.Les
utilisateursnepeuventpasmodifierousupprimerdes
ligneshistoriques.
» Lesutilisateursnepeuventpasmodifierledébutoulafin
delapériodedetemps-systèmedeslignes,qu’ellessoient
courantesouhistoriques.
» LorsquevousutilisezunecommandeUPDATEouDELETE
surunelignecourante,unelignehistoriqueest
automatiquementinsérée.
Unecommandedemiseàjoursurunetabledeversions
systèmesinsèred’abordunecopiedel’ancienneligne,lafin
desapériodedetemps-systèmedevenantl’instantdela
transaction.Celaindiquequelaligneacesséd’êtreune
lignecourante.EnsuiteleSGBDprocèdeàlamiseàjour,
toutenpassantledébutdelapériodedetemps-systèmeà
l’instantdelatransaction.Lalignemiseàjourest
dorénavantunelignecourante.LesdéclencheursUPDATE
deslignesvontêtreactivés,maisceneserapaslecasdes
déclencheursINSERTquoiquedesligneshistoriquesaient
étéinsérées.
UnecommandeDELETEsurune tabledeversionssystèmesnesupprimepasphysiquementleslignesconcernées.Ellemodifieleurfindepériodedetemps-systèmeenyaffectantl’instantcourantdusystème.Celaindiquequeces lignes ont cessé d’être courantes. Elles sont dorénavant des lignes
historiques. Lorsque vous effectuez une commande DELETE, lesdéclencheursDELETEdeslignesconcernéessontactivés.
ConcevoirdesclésprimairespourunetabledeversionssystèmesIl est bien plus facile de désigner les clés primaires dans des tables deversionssystèmesquedansdestablesdepériodesdetemps-application.Eneffet,vousn’avezpasàvouspréoccuperdespériodes.Danslestablesdeversions systèmes, les lignes historiques ne peuvent pas être modifiées.Leur unicité était vérifiée lorsqu’elles étaient des lignes courantes.Maiscommeellesnepeuventplusêtremodifiées,iln’estplusnécessairedes’enassurer.
Si vous ajoutez une contrainte de clé primaire à une table de versionssystèmes à l’aide d’une commande ALTER, elle ne s’appliquera qu’auxlignes courantes, si bien que vous n’aurez donc pas à y faire figurer desinformationsrelativesauxpériodesdanslacommande.Parexemple:
ALTERTABLEemploye_sys
ADDPRIMARYKEY(EmpID);
Celafaitl’affaire.Simpleetefficace.
Appliquerdescontraintesd’intégritéréférentiellesàunetabledeversionssystèmesIlesttoutaussisimpled’ajouterdescontraintesd’intégritéréférentiellesàdestablesdeversionssystèmes,pourlesmêmesraisons.Voiciunexemple:
ALTERTABLEemploye_sys
ADDFOREIGNKEY(EmpDept)
REFERENCESdept_sys(DeptID);
Seulesleslignescourantesétantaffectées,vousn’avezpasàmentionnerlescolonnesdedébutetdefindepériode.
FairedesrequêtessurunetabledeversionssystèmesLa plupart des requêtes sur des tables de versions systèmes cherchent àsavoirquellesdonnéessontvalidesàun instantdonnéousurunepériodedonnée.Pourlepermettre,SQL:2011fournitdenouvellessyntaxes.UtilisezlasyntaxeSYSTEM_TIMEASOFpourdemanderl’informationvalideàuninstantdonné.Parexemple,supposonsquevoussouhaitiezsavoirquiaété employé par l’entreprise le 15 juillet 2013. Vous pourriez former larequêtesuivante:
SELECTEmpID,EmpNom,Sys_Debut,Sys_Fin
FROMemploye_sysFORSYSTEM_TIMEASOF
TIMESTAMP‘2013-07-1500:00:00’;
Cettecommanderetournetoutesleslignesdontledébutdepériodeestégalou antérieur à l’instant spécifié, et dont la fin de période y est égale oupostérieure.
Poursavoircequiétaitvalidesurunepériodedonnée,vouspouvezutiliserune commande similaire, à l’aide de la syntaxe appropriée. Voici unexemple:
SELECTEmpID,EmpNom,Sys_Debut,Sys_Fin
FROMemploye_sysFORSYSTEM_TIMEFROM
TIMESTAMP‘2013-07-0100:00:00’TO
TIMESTAMP‘2013-08-0100:00:00’;
La requête vous retourne toutes les lignes débutant au premier instantindiqué, jusqu’au second, mais sans l’inclure. Vous pourriez autrementutiliserceci:
SELECTEmpID,EmpNom,Sys_Debut,Sys_Fin
FROMemploye_sysFORSYSTEM_TIMEBETWEEN
TIMESTAMP‘2013-07-0100:00:00’AND
TIMESTAMP‘2013-07-3124:59:59’;
La requête vous retourne toutes les lignes débutant au premier instantindiqué,jusqu’ausecond,enl’incluantcettefois.
Siunerequêtesurunetabledeversionssystèmesnespécifiepasd’instant,son comportement pas défaut est de vous retourner toutes les lignescourantesdusystème.Lecodepourraitressembleràceci:
SELECTEmpID,EmpNom,Sys_Debut,Sys_Fin
FROMemploye_sys;
Si vous souhaitez récupérer toutes les lignes d’une table de versionssystèmes, historiques et courantes, vous pouvez le faire en utilisant lasyntaxesuivante:
SELECTEmpID,EmpNom,Sys_Debut,Sys_Fin
FROMemploye_sysFORSYSTEM_TIMEFROM
TIMESTAMP‘2013-07-0100:00:00’TO
TIMESTAMP‘9999-12-3124:59:59’;
Tracerencorepluslesdonnéesavecdestablesbitemporelles
Parfois, vous souhaitez savoir quand un événement s’est passé dans lemonde réel etquand il a été enregistrédans labasededonnées.Danscecas,vouspourriezutiliserunetablequiestàlafoisunetabledeversionssystèmesetunetabledepériodesdetemps-application.Unetelletableestqualifiéedebitemporelle.
Il existe toute une variété de cas où une table bitemporelle peut s’avérerutile.Parexemple,supposonsquel’undevosemployésdéménageetchangealorsd’état,passantdel’OregonàWashington.Vousdeveztenircomptedufaitqueleschargessursonsalairevontchangeràladateofficielledesonnouvelétablissement.Toutefois,iln’estpascertainquelamodificationseraapportéedanslabasededonnéescejourmême.Ilfautdoncenregistrerlesdeuxinstants,etunetablebitemporelleferacelaparfaitement.Latablede
périodes de temps-application conserve les périodes auxquelles ledéménagementaétéconnudelabasededonnées,etlatabledepériodesdetemps-application conserve les périodes auxquelles il a pris légalementeffet.Voiciunexempledecréationd’unetelletable:
CREATETABLEemploye_bt(
EmpIDINTEGER,
EmpDebutDATE,
EmpFinDATE,
EmpDeptInteger
PERIODFOREmpPeriode(EmpDebut,EmpFin),
Sys_DebutTIMESTAMP(12)GENERATEDALWAYS
ASROWSTART,
Sys_FinTIMESTAMP(12)GENERATEDALWAYS
ASROWEND,
EmpNomVARCHAR(30),
EmpRueVARCHAR(40),
EmpVilleVARCHAR(30),
EmpEtatProvinceVARCHAR(2),
EmpCodePostalVARCHAR(10),
PERIODFORSYSTEM_TIME(Sys_Debut,Sys_Fin),
PRIMARYKEY(EmpID,EPeriodeWITHOUTOVERLAPS),
FOREIGNKEY(EDept,PERIODEPeriode)
REFERENCESDept(DeptID,PERIODDPeriode)
)WITHSYSTEMVERSIONING;
Lestablesbitemporellesserventàlafoisdetablesdeversionssystèmesetdetablesdepériodesdetemps-application.L’utilisateurfournitdesvaleurspour lescolonnesdedébutetde findepériode.UnecommandeINSERTdansunetelletablepasseautomatiquementlapériodedetemps-systèmeàladate et l’heure de la transaction. La valeur de la colonne de fin de lapériode de temps-système prend automatiquement la plus grande valeurpossiblepoursontypededonnées.
LescommandesUPDATEetDELETEfonctionnentcommesilatableétaitunetabledepériodesdetemps-application.Demêmequedanslecasd’unetable de versions systèmes, ces commandes n’affectent que les lignescourantes,unelignehistoriqueétantautomatiquementinséréeàchaquefois.
Unerequêtesurunetablebitemporellepeutspécifierunepériodedetemps-système, une période de temps-application, voire les deux. Voici unexempled’utilisationsimultanée:
SELECTEmpID
FROMemploye_btFORSYSTEMTIMEASOF
TIMESTAMP‘2013-07-1500:00:00’
WHEREEmpID=314159AND
EmpPeriodeCONTAINSDATE‘2013-06-20
00:00:00’;
J
Chapitre8Spécifierdesvaleurs
DANSCECHAPITRE:
» Utiliserdesvariablespouréliminerducoderedondant.
» Extraireuneinformationfréquemmentutiliséed’unchampd’unetable.
» Combinerdesvaleursélémentairespourformerdesexpressionscomplexes
’insiste tout au longde ce livre sur l’importancedu rôlede la structured’une base de données dans lemaintien de l’intégrité de cette dernière.Cependant,vousnedevezjamaisoublierquelachoselaplusimportante
est ladonnéeelle-même.Eneffet, lesvaleursquecontiennent lescellulesqui forment les intersections des lignes et des colonnes de la base dedonnéessontlamatièresurlaquellevoustravaillez.
Vouspouvezreprésenterlesvaleursdediversesmanières.Vouspouvezlesreprésenter directement ou les dériver de fonctions et d’expressions. Cechapitredécritlesdiversesformesdevaleursainsiquelesfonctionsetlesexpressions.
Lesfonctionsexaminentdesdonnéesetcalculentunevaleurenfonctiondecesdernières.LesexpressionssontdescombinaisonsdedonnéesqueSQLévaluepourproduireuneseulevaleur.
ValeursSQLreconnaîtdifférentstypesdevaleurs:
» Lesvaleursdelignes.
» Lesvaleurslittérales.
» Lesvariables.
» Lesvariablesspéciales.
» Lesréférencesàdescolonnes.
LESATOMESNESONTPASINDIVISIBLESNONPLUS
Au XIXe siècle, les scientifiques croyaient qu’un atome était le plus
petit composant irréductible de la matière. C’est pourquoi ils
l’appelèrent atome, qui vient du mot grec atomos qui veut dire
indivisible. Aujourd’hui, les scientifiques savent que les atomes ne
sont pas indivisibles. Ils sont formés de protons, de neutrons et
d’électrons. À leur tour, les protons et les neutrons sont faits de
quarks, de gluons et de quarks virtuels. Et peut-être bien que ces
choseselles-mêmesnesontpasindivisibles.Quisait?
Lavaleurd’unchampd’unetableestqualifiéed’atomique,mêmeside
nombreux champs ne sont pas indivisibles. Une valeur DATE est
composéed’unmois,d’uneannéeetd’unjour.UnevaleurTIMESTAMP
estcomposéed’uneheure,deminutes,desecondes,etainsidesuite.
Une valeur REAL ou FLOAT est constituée d’un exposant et d’une
mantisse.UnevaleurCHARestforméedecomposantsauxquelsvous
pouvezaccéderenutilisantSUBSTRING.Parconséquent,qualifierles
champsd’unebasededonnéesd’atomiquesestunabusdelangagesi
l’onsereporteàladéfinitionduterme,àsavoir:lepluspetitmorceau
dematièreinsécable.
Lesvaleursdelignes
Lesvaleurslesplusvisiblesdansunebasesont lesvaleursde lignesdestables.Cesontlesdonnéesquechaqueligned’unetablecontient.Uneligneestgénéralementcomposéedeplusieurséléments,carchaquecolonnedelalignecontientunevaleur.Unchampestl’intersectiond’uneseulecolonneetd’une seule ligne.Un champ contient une valeur scalaire (ou atomique).Unevaleurscalaireouatomiquen’estcomposéequed’elle-même.
LesvaleurslittéralesEn SQL, une valeur est représentée par une variable ou une constante.Contrairementàlavaleurd’uneconstante(quinechangejamais),lavaleurd’une variable peut varier avec le temps. Comme quoi la logique dulangageestparfoisimparable.
Un type important de constante est la valeur littérale. Vous pouvez laconsidérercommeunevaleurWYSIWYG,carWhatYouSeeIsWhatYouGet (ce que vous voyez correspond exactement à ce que vous obtenez).Autrementdit,lareprésentationestlavaleurelle-même.
SQLdisposedenombreuxtypesdedonnéesetdoncdenombreuxtypesdelittéraux. Le Tableau 8.1 présente quelques exemples de littéraux dedifférentstypes.
TABLEAU8.1Deslittérauxdedifférentstypes.
Typededonnées Exempledevaleurlittérale
BIGINT 8589934592
INTEGER 186282
SMALLINT 186
NUMERIC 186282.42
DECIMAL 186282.42
REAL 6.02257E-23
DOUBLEPRECISION 3.1415926535897E00
FLOAT 6.02257E-23
CHARACTER(15) ‘GRECE‘
Note:Contientquinze
caractèresautotaldontdes
espaces.
VARCHAR(CHARACTER
VARYING
‘grecque’
NATIONALCHARACTER(15) ELLAS‘1
Note:Contientquinze
caractèresautotaldontdes
espaces.
NATIONALCHARACTER
VARYING
‘lepton’2
CHARACTERLARGEOBJECT
(CLOB)
(unechaînedecaractères
réellementtrèslongue)
BINARY(4) ‘010011000111000011110001110010
10’
VARBINARY(4)(BINARY
VARYING(4))
‘0100110001110000’
BINARYLARGEOBJECT(512)
(BLOB(512))
(unechaînedeunsetdezéros
réellementtrèslongue)
DATE DATE‘1969-07-20’
TIME(2) TIME‘13.41.32.50’
TIMESTAMP(0)
TIMESTAMP‘1998-05-17-
13.03.16.000000’
TIMEWITHTIMEZONE(4) TIME‘13.41.32.5000-08.00’
TIMESTAMPWITHTIMEZONE(0) TIMESTAMP‘1998-05-17-
13.03.16.0000+02.00’
INTERVALDAY INTERVAL‘7’DAY
Remarquez que les littéraux de type non numérique sont entourésd’apostrophes. Ces délimiteurs permettent d’éviter toute confusion, maisposentparfoisdesproblèmes.
Que se passe-t-il si une chaîne de caractères contient elle-même uneapostrophe?Vousdevezalorsdoubler cette apostrophepourmontrerquel’undesdeuxsignesfaitpartiedelachaîneetn’enmarquedoncpaslafin.Pour dire par exemple ‘L’évaporation de l’eau’, il vous fautécrire‘L’’évaporationdel’’eau‘.
LesvariablesLes littéraux et autres types de constantes sont fort utiles, mais ils neremplacent pas les variables.Dans bien des cas, se passer des variablesrevient à s’imposer une importante, et inutile, surcharge de travail. Unevariabledésigne toutsimplementunequantitédont lavaleurpeutchanger.L’exemplesuivantdevraitvousendémontrerl’utilité.
Supposons que vous soyez le distributeur d’un produit vendu à plusieursclassesdeclients.Vousaccordez lemeilleurprixauxclientsqui achètentdesvolumesimportants,unprixunpeumoinsbonàceuxquiachètentdesquantités moyennes, les personnes qui n’achètent qu’en faible quantitépayant évidemment plein tarif.Vous voulez donc indexer vos prix sur lesquantités achetées. Pour votre produit F-117A, vous décidez defacturer 1,4 fois le prix d’achat aux gros clients (classe C). Vousfacturez 1,5 fois ce prix aux moyens acheteurs (classe B). Enfin, vousfacturez1,6foisvoscoûtsauxpetitsclients(classeA).
Vousstockezlesprixd’achatdevosproduitsetlestarifsauxquelsvouslesrevendezdans une table quevous nommezTARIFS.Pourmettre en place
votre nouvelle structure de prix, vous allez exécuter les commandes SQLsuivantes:
UPDATETARIFS
SETPRIX=COUT*1.4
WHEREPRODUIT=‘F-117A’
ANDCLASSE=‘C’;
UPDATETARIFS
SETPRIX=COUT*1.5
WHEREPRODUIT=‘F-117A’
ANDCLASSE=‘B’;
UPDATETARIFS
SETPRIX=COUT*1.6
WHEREPRODUIT=‘F-117A’
ANDCLASSE=‘A’;
Ce code répond exactement à vos besoins. Mais que se passe-t-il si uncompétiteuragressifveutmangervospartsdemarché?Vousallezdevoirréduirevosmarges.Ilvousfautalorssaisirunecommandetellequecelle-ci:
UPDATETARIFS
SETPRIX=COUT*1.25
WHEREPRODUIT=‘F-117A’
ANDCLASSE=‘C’;
UPDATETARIFS
SETPRIX=COUT*1.35
WHEREPRODUIT=‘F-117A’
ANDCLASSE=‘B’;
UPDATETARIFS
SETPRIX=COUT*1.45
WHEREPRODUIT=‘F-117A’
ANDCLASSE=‘A’;
Sivotremarchéest trèsvolatile,vousdevrezsouvent réécrirevotrecodeSQL. Cela peut devenir rapidement fastidieux, en particulier si les prix
figurentàplusieursendroitsdansvotrecode.Pourrésoudreceproblème,ilsuffitde remplacer les littéraux (telsque1,45) par des variables (tellesquecoefficientA).Vouspourriezalorsprocéderàvosmisesàjourdelamanièresuivante:
UPDATETARIFS
SETPRIX=COST*:coefficientC
WHEREPRODUIT=‘F-117A’
ANDCLASSE=‘C’;
UPDATETARIFS
SETPRIX=COST*:coefficientB
WHEREPRODUIT=‘F-117A’
ANDCLASSE=‘B’;
UPDATETARIFS
SETPRIX=COST*:coefficientA
WHEREPRODUIT=‘F-117A’
ANDCLASSE=‘A’;
Dorénavant,chaquefoisquelesconditionsdumarchévouscontraindrontàmodifier vos prix, vous n’aurez qu’à modifier les valeurs des variablescoefficientA,coefficientBetcoefficientC.
Vousverrezquelesvariablesquevousutilisezdecettemanièresontparfoisnommées paramètres ou encore variables hôtes. Les variables sontappeléesparamètressiellesfigurentdansunmoduledecodeécritenSQL,etvariableshôtessiellesfigurentdansducodeSQLintégré.
LeSQLintégrécorrespondauxinstructionsSQLquisontintégréesdanslecode d’une application écrite dans un langage hôte. Une autre solutionconsisteàutiliserunmoduledelangageSQLpourécriretoutunmoduledecodeSQLquel’applicationappellera.Lechoixentrel’uneetl’autredecesméthodesdépenddevotreimplémentation.
VariablesspécialesSi l’utilisateur d’une machine client se connecte à une base de donnéeshébergée par un serveur, cette connexion est nommée session. Si
l’utilisateurseconnecteàplusieursbasesdedonnées,lasessionassociéeàla connexion la plus récente est considérée comme étant la sessioncourante. Les sessions précédentes sont dites dormantes. SQL définitplusieurs variables spéciales qui se révèlent fort utiles sur un systèmemultiutilisateur.Ellesconserventeneffetlatracedesdifférentsutilisateurs.Voyonsceladeplusprès:
» SESSION_USER:LavariablespécialeSESSION_USER
contientunevaleurégaleàl’identifiantdel’utilisateurdela
sessionSQLcourante.Sivousécrivezunprogrammequi
superviselabasededonnées,vouspouvezinterroger
SESSION_USERpoursavoirquiestentraind’exécuterdes
instructionsSQL.
» CURRENT_USER:UnmoduleSQLpeutdisposerd’un
identificateurd’autorisationpourunutilisateurdonné.
CettevaleureststockéedansCURRENT_USER.Sile
modulen’apasd’identifiantdecetype,lavaleurde
CURRENT_USERestcelledeSESSION_USER.
» SYSTEM_USER:LavariableSYSTEM_USERcontient
l’identifiantd’unutilisateurdusystèmed’exploitation.Cet
identifiantestéventuellementdifférentdeceluiquiFigure
dansunmoduleSQL.Unutilisateurpeutseconnecterau
systèmesouslenomdeLARRY,maisdéclarers’appeler
RESPONSABLEdansunmodule.Lavaleurde
SESSION_USERestalorsRESPONSABLE.Sil’utilisateurne
faitaucuneréférenceexpliciteàl’identificateurdumodule,
etsiCURRENT_USERcontientaussiRESPONSABLE,alorsla
valeurdeSYSTEM_USERestLARRY.
Les variables SESSION_USER, SYSTEM_USER et CURRENT_USERservent à suivre à la trace les accès au système. Vous pouvez tenir unjournal de bord en stockant périodiquement les valeurs de ces variables
dansunetable.Parexemple:
INSERTINTOLOGUTIL(SNAPSHOT)
VALUES(‘Utilisateur‘||SYSTEM_USER||
‘avecID‘||SESSION_USER||
‘activéà‘||CURRENT_TIMESTAMP);
Cetteinstructionproduitl’entréesuivante:
UtilisateurLARRYavecIDRESPONSABLEactivéà
2006-05-
17-14.18.00
RéférencesdecolonnesLes colonnes contiennent une valeur pour chaque ligne d’une table. LesinstructionsSQLseréfèrentsouventàcesvaleurs.Uneréférencecomplèteàunecolonnesecomposedunomde la table,d’unpointetdunomde lacolonne (comme dans TARIFS. PRODUIT). Regardez l’exemplesuivant:
SELECTTARIFS.COUT
FROMTARIFS
WHERETARIFS.PRODUIT=‘F-117A’;
TARIFS.PRODUITestuneréférencedecolonne.Ellecontientlavaleur‘F117-A’.TARIFS.COUTest aussi une référence de colonne,maisvous ne connaîtrez sa valeur que lorsque l’instructionSELECT aura étéexécutée.
Seule la référenceàdescolonnesquise trouventdans la tablecouranteavéritablement un sens. Vous pouvez donc généralement omettre dementionnerlenomdecettetable.Ainsi,l’instructionsuivanteéquivautàlaprécédente:
SELECTCOUT
FROMTARIFS
WHEREPRODUIT=‘F-117A’;
Il peut cependant arriver que vous ayez à manipuler plusieurs tables. Ilarrive que deux tables de la base de données contiennent des colonnesportant le même nom. Si tel est le cas, vous devez utiliser des noms decolonnestotalementqualifiéspourlesdiscriminer.
Parexemple,supposonsquevotresociétédisposedebureauxàKingstonetJeffersonetquevousgériezunelistedesemployéspourchaquesite.Vousnommez EMP_KINGSTON la table des employés de Kingston etEMP_JEFFERSON celle des employés de Jefferson. Vous voulezrécupérerlalistedespersonnelsdontlesnomsapparaissentdanscesdeuxtables.L’instructionSELECTsuivantevousdonnelerésultatvoulu:
SELECTEMP_KINGSTON.NOM,EMP_KINGSTON.PRENOM
FROMEMP_KINGSTON,EMP_JEFFERSON
WHEREEMP_KINGSTON.EMP_ID=
EMP_JEFFERSON.EMP_ID;
Puisque l’identifiant d’un employé est unique quel que soit le site où iltravaille,vouspouvezutilisercetteclécommelienentrelesdeuxtables.Larequêtene retourneque lesnomsdesemployésqui émargent aussibienàKingstonqu’àJefferson.
LesexpressionsdevaleurUne expression est simple ou complexe. Elle peut contenir des valeurslittérales,desnomsdecolonnes,desparamètres,desvariableshôtes,dessous-requêtes, des connecteurs logiques et des opérateurs arithmétiques.Maisquelquesoitsondegrédecomplexité,uneexpressiondoitpouvoirseréduireàuneseulevaleur.
C’est pourquoi les expressions SQL sont aussi nommées expressions devaleur. Il est possible de combiner plusieurs expressions de valeur pourn’en former qu’une seule, dumoment qu’elles se réduisent à des valeursdontlestypessontcompatibles.
SQLdisposedecinqexpressionsdevaleur:
» L’expressiondevaleurchaîne.
» L’expressiondevaleurnumérique.
» L’expressiondevaleurdate/heure.
» L’expressiondevaleurintervalle.
» L’expressiondevaleurconditionnelle.
LesexpressionsdevaleurchaîneLa plus simple des expressions de valeur chaîne est une chaîne decaractères.Maiscetteexpressionpeutaussiêtrelaréférenceàunecolonne,unefonctiond’ensemble,unesous-requêtescalaire,uneexpressionCASE,une expressionCASTou une expression de valeur chaîne complexe. JetraitedesexpressionsCASTetCASEauChapitre9etdessous-requêtesauChapitre12.
Unseulopérateurestdisponiblepourlesexpressionsdevaleurdechaîne:la concaténation. Vous pouvez concaténer n’importe laquelle desexpressionsmentionnéesaudébutdecettesectionpourcréeruneexpressionde chaîne plus complexe.Une paire de lignes verticales(||) représentecet opérateur de concaténation. Le tableau suivant propose quelquesexemplesd’expressiondevaleurdechaîne:
Cetteexpression Produit
‘Beurre‘||‘salé’ ‘Beurresalé’
‘Haricots’||‘‘||‘verts’ ‘Haricotsverts’
PRENOM||‘‘||NOM ‘AndréDupont’
B’1100111’||B’01010011’B’110011101010011’
‘‘||‘Machin’ ‘Machin’
‘Machin’||‘‘ ‘Machin’
‘Ma’||‘‘||‘ch’||‘‘||‘in’ ‘Machin’
Commevouspouvezleconstater,sivousconcaténezunechaîneàuneautredelongueurnulle,lerésultatestidentiqueàlachaîned’origine.
LesexpressionsdevaleurnumériqueLes expressions de valeur numérique vous permettent d’appliquer lesopérateursd’addition,desoustraction,demultiplicationetdedivisionàdestypes de données numériques. L’expression doit pouvoir se réduire à unevaleurnumérique.Lesélémentsquilacomposentpeuventêtrededifférentstypes,maistousdoiventêtrenumériques.Lanaturedurésultatdépenddestypes de données des éléments qui constituent l’expression. Le standardSQL ne spécifie pas strictement le type produit par une combinaison devaleurs numériques. Tout dépend de votre plate-forme. Consultez ladocumentation fournie avec celle-ci pour en apprendre plus sur cettequestion.
Voiciquelquesexemplesd’expressionsdevaleurnumérique:
» 27
» 49+83
» 5*(12–3)
» PROTEINE+GRAISSE+HYDRATECARBONE
» LONGUEUR/5280
» COUT*:coefficientA
Lesexpressionsdevaleurdate/heureLesexpressionsdevaleurdate/heurepermettentd’effectuerdesopérationssur des dates et des heures. Ces expressions peuvent être composéesd’éléments de types DATE, TIME, TIMESTAMP ou INTERVAL. Lerésultat d’une expression de valeur date/heure est toujours de typedate/heure (DATE, TIME ou TIMESTAMP). Par exemple, l’expressionsuivantedonneladatequ’ilseradansunesemaine:
CURRENT_DATE+INTERVAL‘7’DAY
LesheuressontauformatUTC(UniversalTimeCoordinated),c’est-à-direqu’ellessontexpriméesrelativementauméridiendeGreenwich.Maisvouspouvezaussispécifierundécalageafindevousajusteràunfuseauhorairedevotrechoix.Lasyntaxequisuitexprimel’heurelocaledevotresystème:
TIME‘22.55.00’ATLOCAL
Jetezuncoupd’œilsurcetteautresyntaxe,pluslongue:
TIME‘22.55.00’ATTIMEZONEINTERVAL‘-08.00’
HOURTO
MINUTE
Cette expression définit l’heure comme étant celle de Portland dansl’Oregon,quiestinférieurede8heuresàcelleduméridiendeGreenwich.
LesexpressionsdevaleurintervalleSi vous faites la différence entre deux valeurs de type date/ heure, vousobtenez un intervalle. Notez bien que SQL ne vous permet pas d’ajouterdeuxvaleursdetypedate/heure(celan’auraitpasdesens).Sivousajoutezou soustrayez deux intervalles, vous obtenez un nouvel intervalle. Il estaussipossibledemultiplieroudiviserdesintervallesentreeux.
Souvenez-vousqueSQLdisposededeuxtypesd’intervalles :année-moiset jour-heure. Pour lever toute ambiguïté, vous devez spécifier quel typevousutilisezdansuneexpression.Parexemple,l’expressionsuivanteutiliseunintervalleannée-moispourcalculerl’âgethéoriquedevotreretraite:
(ANNIVERSAIRE_60–DATE_COURANTE)YEARTOMONTH
L’exempleci-dessousproduitunintervallede40jours:
INTERVAL‘17’DAY+INTERVAL‘23’DAY
L’exemple qui suit fournit une approximation du nombre de mois durantlesquelsunemèredecinqenfantsestrestéeenceinte:
INTERVAL‘9’MONTH*5
Les intervalles peuvent être négatifs aussi bien que positifs. Ils peuventégalement consister en des expressions de valeur ou des combinaisonsd’expressionsdevaleursquiseréduisentàdesintervalles.
LesexpressionsdevaleurconditionnelleComme son nom l’indique, la valeur d’une expression de valeurconditionnelle dépend d’une condition. Les expressions de valeurconditionnelleCASE,NULLIFetCOALESCEsontbienplus complexesque lesautres typesd’expressions.En fait,ellessontsicomplexesque jen’ai pas assez de place pour en parler ici. Je les traite en détail auChapitre9.
LesfonctionsUne fonction est une opération simple ou modérément complexe que lescommandes usuelles de SQL ne savent pas effectuer, mais qui peut serévélerfortutile.SQLfournitdesfonctionsquieffectuentdestâchesquelecode de l’application écrite dans le langage hôte (celui dans lequel vosinstructionsSQLsontincorporées)devraitautrementeffectuer.SQLdisposededeux catégories principales de fonctions : les fonctionsd’ensemble etlesfonctionsdevaleurs.
Utiliserlesfonctionsd’ensembleLes fonctions d’ensemble s’appliquent à des ensembles de lignes plutôtqu’àuneligneunique.Ellesrenvoienttelleoutellecaractéristiquedujeudelignes courant. Un tel ensemble peut contenir des lignes de la table, ouencore des parties de lignes isolées par une clauseWHERE (je traite endétailde laclauseWHEREauChapitre10). Les programmeurs appellent
quelquefoislesfonctionsd’ensemblefonctionsd’agrégat,carcesfonctionsextraientdesinformationsdeplusieurslignes,lestraitentd’unequelconquemanière et retournent une seule information. Cette réponse est le fruit del’agrégationdesdonnéesquecontiennentleslignes.
Pour illustrer l’utilisation des fonctions d’ensemble, observez leTableau 8.2. Il s’agit d’un tableau nutritionnel, les valeurs étant fourniespour100grammesd’aliments.
UnetablenomméeALIMENTScontientlesinformationsprésentéesdansleTableau8.2.Leschampsvidescontiennent lavaleurNULL.Les fonctionsd’ensemble COUNT, AVG, MAX, MIN et SUM vont vous fournir desinformationsintéressantessurcettetable.
COUNTLafonctionCOUNTvousindiquecombiendelignescomportelatable,oucombiendelignesdelatablerépondentàcertainscritères.L’utilisationlaplustrivialedelafonctionestlasuivante:
TABLEAU8.2Valeursnutritivespour100gd’aliments.
Aliment Calories Protéines
(g)
Graisse
(g)
Hydrate
carboné(g)
Amandesgrillées 627 18,6 57,7 19,6
Asperge20 2,2 0,2 3,6
Bananecrue 85 1,1 0,2 22,2
Boeuf,hamburger
maigre
219 27,4 11,3
Poulet,platallégé 166 31,6 3,4
Opossum,rôti 221 30,2 10,2
Porc,jambon 394 21,9 33,3
Haricots 111 7,6 0,5 19,8
Soda 39 10,0
Pain,blanc 269 8,7 3,2 50,4
Pain,bléentier 243 10,5 3,0 47,7
Brocolis 26 3,1 0,3 4,5
Beurre 716 0,6 81,0 0,4
Bonbons 367 0,5 93,1
Huiled’arachide421 5,7 10,4 81,0
SELECTCOUNT(*)
FROMALIMENTS;
Cetteinstructionvousretournecommevaleur15,carelledénombretoutesles lignes de la table ALIMENTS. L’exemple suivant produit le mêmerésultat:
SELECTCOUNT(CALORIES)
FROMALIMENTS;
Comme chaque ligne de la table comporte une entrée dans la colonneCALORIES, la fonction retourne à nouveau 15.Mais si la colonne avaitcontenudesvaleursnulles,lafonctionnelesauraitpasprisesencompte.
L’instructionsuivanteretourneunevaleurde11,car4des15 lignesde latable contiennent une valeur non définie dans la colonneHYDRATECARBONE:
SELECTCOUNT(HYDRATECARBONE)
FROMALIMENTS;
Unchampd’unetablepeutcontenirunevaleurnullepourdiversesraisons.Leplussouvent,cettevaleurn’estpasencoreconnue.Àmoinsqu’ellen’aitpasencoreétésaisie.Silavaleurvautzéro,ilarrivequel’opérateurchargé
delasaisienerenseignepaslechamp.Cen’estpasunebonnehabitude,carle zéro est une valeur bien définie, que vous pouvez utiliser dans voscalculs.Lavaleurnullen’estpasdéfinie,sibienqueSQLn’enfaitrien.Lesphrases«Lesodanecontientpasdegraisse»et«Jenesaispascombiendegraissecontientlesoda»nesontpasdutoutéquivalentes!
Vous pouvez aussi utiliser la fonction COUNT en combinaison avec laclauseDISTINCTpourdéterminercombiendevaleursdistinctesexistentdansunecolonne.Parexemple:
SELECTCOUNT(DISTINCTGRAISSE)
FROMALIMENTS;
Laréponsequeretournecetteinstructionest12.Vouspouvezvoirque100gd’asperges contiennent autant de graisse que100 g de bananes (0,2 g), etque100gdeharicotscontiennentautantdegraisseque100gdebonbonssucrés (0,5 g). La table ne contient donc que 12 valeurs distinctes degraisse.
AVGLa fonction calcule et retourne la moyenne des valeurs de la colonnespécifiée.Bien entendu, vousnepouvezutiliser la fonctionAVGque surdescolonnesquicontiennentdesvaleursnumériques,commeparexempledans:
SELECTAVG(GRAISSE)
FROMALIMENTS;
Lerésultatest15,37.Cenombreestgrandàcausedelaprésencedubeurredans la table. Vous vous demandez peut-être quelle valeur produiraitl’instruction si vous ne teniez pas compte de cet aliment. Pour le savoir,utilisezuneclauseWHEREdelamanièresuivante:
SELECTAVG(GRAISSE)
FROMALIMENTS
WHEREALIMENT<>‘Beurre’;
Lavaleurmoyennetombeà10,32gpour100gd’aliment.
MAXLafonctionMAXvousretournelavaleurmaximaletrouvéedanslacolonnespécifiée.L’instructionsuivanterenvoie81(lateneurengraissede100gdebeurre):
SELECTMAX(GRAISSE)
FROMALIMENTS;
MINLafonctionMINvousretournelavaleurminimalequisetrouvedansunecolonne.L’instructionsuivanterenvoie0,4,carlafonctionnetraitepaslesvaleursnullescommedeszéros:
SELECTMIN(CARBOHYDRATE)
FROMALIMENTS;
SUMLa fonction SUM vous retourne la somme de toutes les valeurs d’unecolonne. L’instruction suivante renvoie 3 924, ce qui correspond au totaldescaloriesdes15aliments:
SELECTSUM(CALORIES)
FROMALIMENTS;
LesfonctionsdevaleursBeaucoup d’opérations peuvent être appliquées dans des contextesdifférents.Commevousavezbesoind’utiliserfréquemmentcesopérations,vouspouvezlesincorporerdansducodeSQLsouslaformedefonctionsdevaleurs. SQL ne dispose que de peu de fonctions de valeurs si on le
compareàdesSGBDtelsqu’AccessouFoxPro,maiscesontprobablementlesseulesdontvousvousservirezrégulièrement.SQLutiliselestroistypesdefonctionsdevaleurssuivants:
» Lesfonctionsdevaleurchaîne.
» Lesfonctionsdevaleurnumérique.
» Lesfonctionsdevaleurdate/heure.
» Lesfonctionsdevaleurintervalle
LesfonctionsdevaleurchaîneLesfonctionsdevaleurchaînereçoiventunechaînedecaractèresenentréeetproduisentuneautrechaînedecaractèresensortie.SQLdisposedesixfonctionsdecetype:
» SUBSTRING
» SUBSTRINGSIMILAR
» SUBSTRING_REGEX
» TRANSLSATE_REGEX
» OVERLAY
» UPPER
» LOWER
» TRIM
» TRANSLATE
» CONVERT
SUBSTRING
Utilisez la fonction SUBSTRING pour extraire une partie d’une chaînesource. La chaîne extraite est du même type que la chaîne source. Parexemple,silachaînesourceestdutypeCHARACTERVARYING,ilenirademêmepourlasous-chaîne.
LasyntaxedeSUBSTRINGestlasuivante:
SUBSTRING(valeur_chaîneFROMdébut[FOR
longueur])
LaclausequiFigureentrecrochets ([])estoptionnelle.Lachaîneextraitede valeur_chaîne commence au caractère repéré par début et seprolongesur longueurcaractères.Si laclauseFORn’estpasmentionnée,l’extractionsepoursuitjusqu’àlafindelachaînesource.Parexemple:
SUBSTRING(‘Pain,bléentier’FROM7FOR6)
La chaîne extraite est ‘blé en’. Elle commence au septième caractère etprendsixcaractères.SUBSTRINGnesemblepasaprioriêtreunefonctiontrès intéressante.Si j’aiunevaleur littérale ‘Pain,blé entier’, jen’aipasbesoind’unefonctionpoursavoiràquoicorrespondentlessixcaractèresàpartirduseptième.Cependant,SUBSTRINGestunefonctiontrèsutile,carlavaleurqu’ellemanipulen’apasbesoind’êtreunlittéral.Ilpeuts’agirden’importe quelle expression qui correspond à une chaîne. Ainsi, il estparfaitement possible d’utiliser une variable qui se nommeobjetalimentet qui prend des valeurs différentes selon le contexte.L’expression suivante permettrait d’extraire une chaîned’objetaliment, et ce quelle que soit la valeur chaîne courantereprésentéeparcettevariable:
SUBSTRING(:objetalimentFROM7FOR6)
Touteslesfonctionsdevaleurseressemblent,encesensqu’ellespeuventmanipulerdesexpressionsoudesvaleurslittérales.
VousdevezfaireattentionàquelquespetiteschosesquandvousutilisezlafonctionSUBSTRING.Vérifiez que la sous-chaîne que vous décrivez estbieninclusedanslachaînesource.Sivousdemandezuneextractionàpartirduseptièmecaractère,maisquelachaînesourcen’encomportequequatre,
la fonction vous retournera une valeur nulle. Par conséquent, vous deveztoujours avoir une idée relativement précise de la forme de vos donnéesavant d’appliquer SUBSTRING. Ne spécifiez pas non plus de valeursnégatives,carlafind’unechaînenepeutprécédersondébut.
SiunecolonneestdetypeVARCHAR,vousnesavezpasaprioriquelleestsalongueurpourunelignedonnée.Maisl’absencedecette informationneposepasdeproblèmeàlafonctionSUBSTRING.Silalongueurquevousspécifiezesttropimportante,SUBSTRINGvousrenverratoutcequ’elleaputrouver.Elleneretournerapasuneerreur.
Parexemple,supposonsquevousutilisiezl’instruction:
SELECT*FROMALIMENTS
WHERESUBSTRING(ALIMENTFROM7FOR12)=
‘blé’;
CetteinstructionretournelalignequicorresponddanslatableALIMENTSaupainaubléentier, alorsmêmeque lacolonneALIMENTcontient unevaleurdontlalongueurestinférieureà18caractères(‘pain,blé’).
Si un opérande (une valeur à partir de laquelle un opérateur dérive uneautre valeur) de SUBSTRING contient une valeur nulle, la fonctionretourneraunevaleurnulle.
SUBSTRINGSIMILARCette fonction est triadique (cela signifie qu’elle opère sur troisparamètres).Cestroisparamètressontunechaînedecaractèresource,unechaînedemotif(stringpattern)etuncaractèred’échappement.Elleutiliseensuite les motifs correspondants (en fonction des expressions régulièresbasées sur POSIX) pour extraire et retourner une chaîne résultat dans lachaînedecaractèresource.
Deuxinstancesducaractèred’échappement,chacunesuivied’unguillemet,servent à décomposer la chaîne de motif en trois parties. En voici unexemple:
SupposezquelachaînedecaractèresourceSsoit:‘Ilyaquatre-vingt-septans, nos pères ont fondé sur ce continent une nouvelle nation’. Supposez
ensuitequelachaînedemotifRsoit‘quatre‘/”’sept’/”’années’,oùlabarreobliqueestlecaractèred’échappement.
Alors
SUBSTRINGSSIMILARTOR;
retourneun résultatqui correspondaumilieude la chaînedemotif ‘sept’dansnotreexemple.
SUBSTRING_REGEXSUBSTRING_REGEX recherche une chaîne de motif d’expressionrégulière XQuery et retourne une occurrence de la sous-chaînecorrespondante.
Conformémentaustandard international ISO/IECJTC1/SC32, la syntaxedel’expressionrégulièred’unesous-chaîneestlasuivante:
SUBSTRING_REGEX<leftparen>
<XQuerypattern>[FLAG<XQueryoptionflag>
]
IN<regexsubjectstring>
[FROM<startposition>]
[USING<charlengthunits>]
[OCCURRENCE<regexoccurrence>]
{GROUP<regexcapturegroup>]<rightparen>
<XQuerypattern> est l’expression de chaîne de caractère dont lavaleurestuneexpressionrégulièreXQuery.
<XQuery option flag> est une chaîne de caractère optionnellecorrespondant à l’argument $flags de la fonction [XQuery F & O]fn:match.
<regexsubjectstring>estlachaînedecaractèrerecherchéequidevraitcorrespondreau<Xquerypattern>.
<start position> est une valeur numérique exacte optionnelle àl’échelle 0 qui indique la position du caractère où doit commencer larecherche(savaleurpardéfautest1).
<charlengthunits> estCHARACTERSou OCTETS, indiquantl’unitédanslaquelle<startposition>estmesurée. (SavaleurpardéfautestCHARACTERS).
<regexoccurrence> est une valeur numérique exacte optionnelle àl’échelle 0, qui indique quelle occurrence d’une correspondance estdemandée(Savaleurpardéfautest1).
<regex capture group> est une valeur numérique exacteoptionnelle à l’échelle 0 qui indique le groupe de capture d’unecorrespondance souhaitée. (Sa valeur par défaut est 0, ce qui indiquel’occurrenceentière).
Voiciquelquesexemplesd’utilisationdeSUBSTRING_REGEX:
SUBSTRING_REGEX(‘\p{L}*’IN‘Justdo
it.’)=‘Just’
SUBSTRING_REGEX(‘\p{L}*’IN‘Justdoit.’FROM
2)=‘ust’
SUBSTRING_REGEX(‘\p{L}*’IN‘Justdoit.’
OCCURRENCE2)
=‘do’
SUBSTRING_REGEX(‘(do)(\p{L}*’IN‘Justdoit.’
GROUP
2)=‘it’
TRANSLATE_REGEXTRANSLATE_REGEX recherche une chaîne de motif d’expressionrégulièreXQueryetretournelachaîneavecl’uneoutouteslesoccurrencesde l’expression régulière XQuery remplacée par une chaîne deremplacementXQuery.
Conformémentaustandard international ISO/IECJTC1/SC32, la syntaxed’unetranslitérationregexestlasuivante:
TRANSLATE_REGEX<leftparen>
<XQuerypattern>[FLAG<XQueryoptionflag>]
IN<regexsubjectstring>
[WITH<regexreplacementstring>]
[FROM<startposition>]
[USING<charlengthunits>]
[OCCURRENCE<regextransliterationoccurrence>]
<right
paren>
<regextransliterationoccurrence>::=
<regexoccurrence>
|ALL
Où:
» <regexreplacementstring>estunechaînede
caractèredontlavaleurconvientàl’utilisationde
l’argument$replacementdelafonction[XQuery
F&O]fn:replace.Savaleurpardéfautestlachaîne
zérodelongueur.
» <regextransliterationoccurrence>estsoitlemot
cléALLsoitunevaleurnumériqueexacteàl’échelle0,
indiquantquelleoccurrencedelacorrespondance
recherchée(pardéfautALL).
Voiciquelquesexemplesavecunechaînesansremplacement:
TRANSLATE_REGEX(‘i’IN‘Billdidsit.’)=‘Bll
ddst.’
TRANSLATE_REGEX(‘i’IN‘Billdidsit.’
OCCURRENCEALL)=
‘Bllddst.’
TRANSLATE_REGEX(‘i’IN‘Billdidsit.’FROM5)=
‘Bill
ddst.’
TRANSLATE_REGEX(‘i’IN‘Billdidsit.’
Occurrence2)=
‘Billddsit.’
Voiciquelquesexemplesavecunechaînederemplacement:
TRANSLATE_REGEX(‘i’IN‘Billdidsit.’WITH‘a’)
=‘Ball
dadsat.‘
TRANSLATE_REGEX(‘i’IN‘Billdidsit.’WITH‘a’
OCCUR-
RENCEALL)=‘Balldad
sat.’
TRANSLATE_REGEX(‘i’IN‘Billdidsit.’WITH‘a’
OCCUR-
RENCE2)=‘Billdad
sit.’
TRANSLATE_REGEX(‘i’IN‘Billdidsit.’WITH‘a’
FROM5)
=‘Billdadsat.’
OVERLAYOVERLAY remplace une sous-chaîne donnée d’une chaîne (spécifiée parunepositiondedépartnumériquedonnéeetparune longueurdonnée)parunechaînederemplacement.Quandlalongueurspécifiéedelasous-chaîneest zéro, onne supprime riendans la chaîneoriginale.Mais la chaînederemplacement est insérée dans la chaîne originale en commençant à lapositiondedépartspécifiée.
UPPERLa fonction UPPER convertit une chaîne de caractères en majuscules,commel’illustrentlesexemplesdutableausuivant:
Cetteinstruction Retourne
UPPER(‘e.e.cummings’) ‘E.E.CUMMINGS’
UPPER(‘IsaacNewton,Ph.D’) ‘ISAACNEWTON,PH.D.’
LafonctionUPPERn’affectepasleschaînesquisontdéjàenmajuscules.
LOWERLa fonction LOWER convertit une chaîne de caractères en minuscules,commel’illustrentlesexemplesdutableausuivant:
Cetteinstruction Retourne
LOWER(‘TAXES’) ‘taxes’
LOWER(‘E.E.Cummings’) ‘e.e.cummings’
LafonctionLOWERn’affectepasleschaînesquisontdéjàenminuscules.
TRIMLa fonction TRIM supprime les blancs (ou d’autres caractère) qui setrouvent au début ou à la fin d’une chaîne. Voici quelques exemplesd’utilisationdeTRIM:
Cetteinstruction Retourne
TRIM(LEADING‘‘FROM‘sens‘) ‘sens‘
TRIM(TRAILING‘‘FROM‘sens‘) ‘sens’
TRIM(BOTH‘‘FROM‘sens‘) ‘sens’
TRIM(BOTH‘s’from‘sens’) ‘en’
Lecaractèrepardéfautsuppriméestl’espace.Lasyntaxesuivanteestdonclégale:
TRIM(BOTHFRsOM‘sens‘)
Vousobtenezlemêmerésultatqu’avecletroisièmeexempledelatable.
TRANSLATEetCONVERTLesfonctionsTRANSLATEetCONVERTprennentunechaînesourcedansunjeudecaractèreset laconvertissentenunechaînedansunautrejeudecaractères.Parexemple,vouspourriezconvertirunechaînedel’anglaisenkanjioudel’hébreuenfrançais.Lesfonctionsdeconversionquispécifientces transformationsdépendentde l’implémentation.Reportez-vousàvotrepropresystèmepourplusdedétails.
Sitraduired’unlangagedansunautreétaitaussisimplequed’invoquerlafonction SQL TRANSLATE, ce serait formidable. Malheureusement, cen’est pas aussi facile. TRANSLATE se contente de convertir le jeu decaractères d’une chaîne. Par exemple, cette fonction peut convertir‘Ellas’ en‘Ellas’, mais elle ne peut pas traduire ‘Ellas’ en‘Grèce’.
LesfonctionsdevaleurnumériqueLesfonctionsdevaleurnumériqueprennentdesdonnéesdedifférentstypesenentrée,maisellesgénèrenttoujoursunevaleurnumériqueensortie.SQLdisposedequinzedecesfonctions:
» Position(POSITION)
» Fonctiond’occurrencesregex(OCCURRENCES_REGEX)
» Positionregex(POSITION_REGEX)
» Extraction(EXTRACT)
» Longueur(CHAR_LENGTH,CHARACTER_LENGTH,OCTET_
LENGTH)
» Cardinalité(CARDINALITY)
» Valeurabsolue(ABS)
» Modulo(MOD)
» Logarithmenaturel(LN)
» Exponentielle(EXP)
» Puissance(POWER)
» Racinecarrée(SQRT)
» Valeurapprochéebasse(FLOOR)
» Valeurapprochéehaute(CEIL,CEILING)
» Fonctiond’intervalle(WIDTH_BUCKET)
POSITIONPOSITIONrecherchelachaîneciblespécifiéedansunechaînesourceetretourne la position du premier caractère de la cible. Pour une chaîne decaractères,lasyntaxeestlasuivante:
POSITION(cibleINsource[USINGcharlength
units])
VouspouvezspécifieruneunitédelongueurautrequeCHARACTER,maisc’estrare.SivousutilisezdescaractèresUnicodeselonletypelecaractèrepeutêtrede8,16,ou32bitsdelong.Silecaractèreestde16ou32bitsdelong,vouspouvezexplicitementspécifier8bitsavecUSINGOCTETS.
Pourunechaînebinaire,lasyntaxeestlasuivante
POSITION(cibleINsource)
Si lavaleurde lacibleestégaleàunesous-chaînede longueur identiquedesoctetscontigusdanslachaînesource,alorslerésultatestsupérieurau
nombred’octetsquiprécèdeledébutdupremiercommesous-chaîne.
Letableausuivantprésentequelquesexemples:
Cetteinstruction Retourne
POSITION(‘P’IN‘Pain,bléentier’) 1
POSITION(‘Pai’IN‘Pain,bléentier’) 1
POSITION(‘b’IN‘Pain,bléentier’) 7
POSITION(‘bli’IN‘Pain,bléentier’) 0
POSITION(‘‘IN‘Pain,bléentier’) 1
POSITION(‘01001001’IN
‘001100010100100100100110’
2
Silafonctionnetrouvepaslachaînecible,elleretournelavaleurzéro.Sila chaîne cible est vide (comme dans le dernier exemple de caractère),POSITIONretournetoujoursun.Sin’importelequeldesdeuxopérandesdelafonctionestunevaleurnulle,lafonctionretourneunevaleurnulle.
OCCURRENCES_REGEXOCCURRENCES_REGEX est une fonction numérique qui retourne lenombredecorrespondancesd’uneexpressionrégulièredansunechaîne.Sasyntaxeestlasuivante:
OCCURRENCES_REGEX<leftparen>
<XQuerypattern>[FLAG<XQueryoptionflag>]
IN<regexsubjectstring>
[FROM<startposition>]
[USING<charlengthunits>]<rightparen>
Envoiciquelquesexemples:
OCCURRENCES_REGEX(‘i’IN‘Billdidsit.’)=3
OCCURRENCES_REGEX(‘i’IN‘Billdidsit.’FROM
5)=2
OCCURRENCES_REGEX(‘I’IN‘Billdidsit.’)=0
POSITION_REGEXPOSITION_REGEXest une fonction numérique qui retourne la positionde départ d’une correspondance ou en plus la fin d’une correspondanced’uneexpressionrégulièredansunechaîne.Envoicilasyntaxe:
POSITION_REGEX<leftparen>[<regexposition
startor
after>]
<XQuerypattern>[FLAG<XQueryoptionflag>]
IN<regexsubjectstring>
[FROM<startposition>]
[USING<charlengthunits>]
[OCCURRENCE<regexoccurrence>]
[GROUP<regexcapturegroup>]<rightparen>
<regexpositionstartorafter>::=START|
AFTER
Etquelquesexemples:
POSITION_REGEX(‘i’IN‘Billdidsit.’)=2
POSITION_REGEX(START‘i’IN‘Billdidsit.’)=
2
POSITION_REGEX(AFTER‘i’IN‘Billdidsit.’)=
3
POSITION_REGEX(‘i’IN‘Billdidsit.’FROM5)=
7
POSITION_REGEX(‘i’IN‘Billdidsit.’
OCCURRENCE2)=
7
POSITION_REGEX(‘I’IN‘Billdidsit.’)=0
EXTRACTLa fonction EXTRACT extrait un champ d’une date/heure ou d’unintervalle.Parexemple,l’instructionsuivanteretourne08:
EXTRACT(MONTHFROMDATE‘2000-08-20’)
CHARACTER_LENGTHLa fonctionCHARACTER_LENGTHdonne le nombre de caractères dansunechaînedecaractères.Parexemple,l’instructionsuivanteretourne13:
CHARACTER_LENGTH(‘Opossum,rôti’)
Commejel’aifaitremarquerplushautausujetdelafonctionSUBSTRING,cette fonction n’est pas particulièrement utile si ses arguments sont deslittéraux tels que ‘Opossum, rôti’. Je peux tout aussi bien écrire 13 queCHARACTER_LENGTH(‘Opossum,rôti’). En fait, cette fonctionne se révèle intéressante que si vous lui transmettez une variable enargument.
OCTET_LENGTHDans la terminologie informatique, un octet est une suite de huit bits.Presque tous les ordinateurs utilisent des octets pour représenter lescaractères alphanumériques simples. Mais des langues plus complexes(commelechinois)nécessitent16bitspourcoderleurssignes.LafonctionOCTET_LENGTHcompteetretournelenombred’octetsdansunechaîne.S’il s’agit d’une suite de bits, la fonction renvoie la quantité d’octetsnécessairepourstockertouscesbits.Sic’estunechaîneécriteenfrançais(un octet par caractère), la fonction retourne le nombre de caractèresqu’ellecontient.Silachaîneestécriteenchinois,elleretournedeuxfoislenombredecaractèresquecontientlachaîne.Lachaînesuivante:
OCTET_LENGTH(‘Haricots’)renvoie
8
donnecomme résultat 11, car chaque caractèrepeut être codé surun seuloctet.
Certainsjeuxdecaractèresutilisentunnombred’octetsdifférentselonlescaractères. En particulier, quelques jeux de caractères, qui sont desmélanges de caractères kanji et latins, se servent de caractèresd’échappement pour basculer entre les deux alphabets. Par exemple, unechaîne formée de kanji et de latin pourrait contenir 30 caractères etrequérir30octetssitouslescaractèressontlatins,62octetss’ilssonttouskanji (60 octets plus les symboles d’échappement de début et de fin)et150octetssic’estunealternancedecaractèreslatinsetkanji(carchaquecaractère kanji requiert deux octets, plus un octet pour les caractèresd’échappementdedébutetdefin).LafonctionOCTET_LENGTHrenvoielenombred’octetsdontvousavezbesoinpourstockerlachaîne.
CARDINALITYLacardinalitéestlenombred’élémentsd’unensemble.Elleconcernedoncles collections (tableaux, ensembles, etc.) dans lesquelles chaque élémentest une valeur possédant un certain type de donnée. En voici un exempled’utilisation:
CARDINALITY(EquipeFoot)
Cettefonctiondevraitnormalementrenvoyer11,àmoinsqu’uneexpulsionn’aitdéjàeulieu...Untableauestunecollectionordonnéed’éléments.Unensemblemultipleestunecollectionnonordonnéed’éléments.Danslecasd’uneéquipedefootball,dontlacompositionvarieàchaquematchetoùdesurcroîtunmêmejoueurpeutoccuperdespostesdifférents, lesensemblesmultiplessontmieuxadaptésquelestableaux.
ARRAY_MAX_CARDINALITYLafonctionCARDINALITYretournelenombred’élémentsdansletableauoul’ensemblemultiplespécifié,cequinevousindiquepaslemaximumdecardinalitéquiétaitattribuéautableau.Orcetteinformationpeutvousêtreutiledansdenombreuxcas.C’estpourquoiSQL:2011aajoutéunenouvellefonction AR-RAY_MAX_CARDINALITY. Comme vous pouvez le
supposer,elleretournelacardinalitémaximaledutableauspécifié.Iln’yapasencoredecardinalitémaximalepourlesensemblesmultiples.
TRIM_ARRAYLafonctionTRIMsupprimelepremierouderniercaractèred’unechaîne,alorsque la fonctionTRIM_ARRAYsupprime lesderniersélémentsd’untableau.
PoursupprimerlestroisderniersélémentsdutableauALIMENT,utilisezlasyntaxesuivante:
TRIM_ARRAY(ALIMENT,3)
ABSLa fonctionABS retourne la valeur absolue d’une expression numérique.Exemple:
ABS(-273)
renvoie273.
MODLa fonction MOD retourne le reste de la division entière de deuxexpressionsnumériques.Exemple:
MOD(3,2)
renvoie1(modulode3divisépar2).
LNLafonctionLNretournelelogarithmenatureld’uneexpressionnumérique.Exemple:
LN(9)
renvoie quelque chose comme 2,197224577. Le nombre de chiffresdécimauxdépenddel’implémentation.
EXPLa fonction EXP retourne l’exponentielle d’une expression numérique(c’est-à-dire la base des logarithmes naturels, e, à la puissance spécifiéeparl’expression).Exemple:
EXP(2)
renvoiequelquechosecomme7,389056.Lenombredechiffresdécimauxdépenddel’implémentation.
POWERLa fonction POWER retourne la valeur de la première expressionnumériqueélevéeàlapuissanceindiquéeparlaseconde.
Exemple:
POWER(2,8)
renvoie 256, soit 2 élevé à la puissance 8 (c’est le plus grand entierenregistrabledansunoctet).
SQRTLa fonctionSQRT retourne la racine carrée de l’expression numérique.Exemple:
SQRT(4)
renvoie2,laracinecarréede4.
FLOORLafonctionFLOOR retourne laplusgrandevaleurentière immédiatementinférieureàcelledel’expressionnumérique.
Exemple:
FLOOR(3.141592)
renvoie3.0.
CEILouCEILINGLa fonctionCEIL (ouCEILING) retourne la plus petite valeur entièreimmédiatementsupérieureàcelledel’expressionnumérique.Exemple:
CEIL(3.141592)
renvoie4.0.
WIDTH_BUCKETLa fonction WIDTH_BUCKET, qui est utilisée dans le traitementd’applicationenligne(OLAP),comportequatrearguments.Ellerenvoieunnombrecomprisentre0etlavaleurdel’argumentfinalplus1.Elleaffectele premier argument à un partage régulier de l’intervalle défini par ledeuxièmeetletroisièmeargument.Silepremierargumentn’appartientpasàcetintervalle,lafonctionretourne0(pluspetitquelalimiteinférieure)ouledernierargumentplus1(plusgrandquelalimitesupérieure).Exemple:
WIDTH_BUCKET(PI,0,9,5)
PIestuneconstanteprédéfiniedeSQLdontlavaleurest3,141592.Cetteinstructionpartagel’intervalleallantdezéroàneufencinqsegmentségaux(chacun représentedoncune longueurdedeuxunités).LavaleurdePI setrouvedanslesecond«godet»(entredeuxetquatre).Lafonctionrenvoiedonclavaleur2.
Fonctionsdevaleurdate/heureSQLdisposede trois fonctionsqui retournentdes informationssur ladatecourante,l’heurecouranteoulesdeux.CUR-RENT_DATErenvoieladatesystème, CURRENT_TIME donne l’heure courante, et
CURRENT_TIMESTAMP retourne la date et l’heure courantes.CURRENT_DATE n’accepte aucun argument. Par contre,CURRENT_TIME et CURRENT_TIMESTAMP prennent un argument.Celui-ci spécifie la précision des secondes. Les types de donnéesdate/heure sontdécrits auChapitre2.Le conceptdeprécisiony est aussiprécisé.
Le tableau suivant présente quelques exemples d’utilisation de cesfonctions:
Cetteinstruction Retourne
CURRENT_DATE 2006-12-31
CURRENT_TIME(1) 08:36:57.3
CURRENT_TIMESTAMP(2) 2006123108:36:57.38
La date que CURRENT_DATE retourne est de type DATE et nonCHARACTER. L’heure fournie par CURRENT_TIME est de type TIME,tandis que la combinaison date/heure donnée par CURRENT_TI-MESTAMP est de type TIMESTAMP. Comme SQL récupère cesinformations en interrogeant l’horloge de votre ordinateur, elles sonttoujourscorrectespourlefuseauhorairedanslequelcelui-cisetrouve.
Sivousvoulez traiter lesdates et lesheures sous la formedechaînesdecaractères afin d’utiliser les fonctions quimanipulent ces dernières, vouspouvezprocéderàuneconversionde typeenutilisant l’expressionCASTdécriteauChapitre9.
FonctionsdevaleurintervalleUne fonction de valeur intervalle nommée ABS a été introduite dansSQL:1999.ElleestsimilaireàlafonctiondevaleurnumériqueABS,maiselleopèresurdesdonnéesdetypeintervalleetnondetypenumérique.ABSprendunseulopérandeetretourneunintervalledeprécisionidentiquequinecomportepasdevaleurnégative.Envoiciunexemple:
ABS(TIME‘11:31:00’–TIME‘12:31:00’)
Lerésultatest
INTERVAL+’1:00:00’HOURTOSECOND
A
Chapitre9ExpressionsSQLavancées
DANSCECHAPITRE:
» UtiliserdesexpressionsconditionnellesCASE.
» Convertirdesdonnéesd’untypedansunautre.
» Gagnerdutempsdesaisieenutilisantdesexpressions.
uChapitre 2, SQL est décrit comme un sous-langage de données. Enfait,saseulefonctionconsisteàmanipulerdesdonnéesdansunebase.SQL manque des nombreuses fonctionnalités d’un langage procédural
conventionnel.Ilenrésultequelesdéveloppeursdoiventpassersanscessede SQL à un autre langage pour contrôler le flux de l’exécution. Cesincessants va-et-vient ralentissent le développement et affectent lesperformanceslorsdel’exécution.Lesproblèmesdeperformancesliésauxlimitations de SQL ont conduit ses concepteurs à lui ajouter desfonctionnalités supplémentaires lors de chaque sortie d’une nouvelleversion du standard. L’une des fonctionnalités récentes de SQL,l’expressionCASE,permetdeconstruiredesstructuresconditionnelles.
Une autre fonctionnalité, l’expression CAST, facilite la conversion desdonnées d’une table d’un type vers un autre (c’est ce que l’on appelle letranstypage). Une troisième fonctionnalité, l’évaluation simultanée deplusieurs valeurs, permet de traiter une liste de valeurs là où vous nepouviezauparavantn’entraiterqu’uneseule.Parexemple,sivotrelistedevaleursestunesériedecolonnesd’unetable,vouspouvezmaintenantleurappliqueruneopérationenunefoisenutilisantunesyntaxefortsimple.
LesexpressionsconditionnellesCASE
Chaque langage informatique digne de ce nom comporte une expressionconditionnelle. En fait, la plupart des langages en ont plusieurs. La pluscourantedesexpressionsconditionnellesestsansdoutelastructureIF...THEN...ELSE...ENDIF.SilaconditionquisuitlemotcléIFestvérifiée, leblocdecommandesqui suit lemotcléTHENest exécuté.Sicetteconditionn’estpasvérifiée,c’estleblocdecommandesquisuitELSEqui est exécuté. Le mot cléENDIF signale la fin de la structure. Cettestructurepermetdegérerdesdécisionsàuneoudeuxissues.Ellen’estpasadaptéeauxdécisionspluscomplexes.
La plupart des langages complets ont une instruction du genreCASEquigèrel’exécutiondeplusieurstâchesàpartird’autantdeconditions.
SQLdiffèredesautreslangagesencesensqueCASEestuneexpressionetnon une instruction. En tant que telle, CASE est simplement un élémentd’une instruction et non une instruction en soi. Avec SQL, vous pouvezplacer une expression CASE quasiment partout où une valeur peut êtreutilisée. Lors de l’exécution, l’expression CASE est remplacée par unevaleur.L’instructionCASEquevoustrouvezdanslesautreslangagesn’estpasévaluéeàunevaleur,maiselleexécuteunblocd’instructions.
Vouspouvezutiliserl’expressionCASEcommesuit:
» Utiliserl’expressionavecdescritèresderecherche.
CASErechercheleslignesd’unetablepourlesquellesles
critèresspécifiéssontvérifiés.SiCASEtrouveuneligne
pourlaquellecescritèressontévaluéscommeétantvrais,
l’instructionquicontientl’expressionCASEestappliquéeà
cetteligne.
» Utiliserl’expressionCASEpourcomparerunchamp
d’unetableàlavaleurspécifiée.Lerésultatde
l’instructionquicontientl’expressionCASEdépenddela
valeurquecontientlechamp.
Lessectionsquisuivent,«UtiliserCASEavecdescritèresderecherche»et « Utiliser CASE avec des valeurs », vous permettront de mieuxappréhender ces concepts. Vous trouverez tout d’abord deux exemplesd’utilisationdeCASEavecdescritèresderecherche.Undecesexemplesrecherche des valeurs dans une table et les modifie en fonction d’unecertainecondition.Lasecondesectionproposedeuxexemplesd’utilisationdelaformedeCASEavecdesvaleurs.
UtiliserCASEavecdescritèresderechercheUneutilisationintéressantedel’expressionCASEestlarecherchedansunetabledelignesquivérifientuncritèrederecherche.SivousutilisezCASEdecettemanière,l’expressionadopteralasyntaxesuivante:
CASE
WHENcritere1THENresultat1
WHENcritere2THENresultat2
...
WHENcriterenTHENresultatn
ELSEresultatx
END
CASE examine la première des lignes qualifiées (la première ligne quirépond au critère de la clauseWHERE s’il y en a une) pour évaluer lecritere1. Si cette condition est vérifiée, l’expressionCASEprend lavaleurresult1. Sinon, l’expressionCASE évalue lecritere2. S’ilestvérifié,l’expressionCASEprendlavaleurresult2,etainsidesuite.Si aucun des critères n’est vérifié, l’expression CASE prend la valeurresultatx.LaclauseELSEestoptionnelle.Sil’expressionn’apasdeclauseELSE et qu’aucun des critères n’est vérifié, elle prend la valeurnulle.Unefoisl’instructionSQLquicontientl’expressionCASEappliquée
àlapremièrelignequalifiéedelatable,elletraitelalignesuivante,etcejusqu’àcequelatablesoitentièrementparcourue.
ModifierdesvaleursenfonctiondecritèreVouspouvezutiliseruneexpressionCASEdans une instructionSQLà laplaceden’importequellevaleur.Parexemple,CASEpeutêtreincorporéedansune instructionUPDATEpoureffectuerplusieursmodificationsdansunetableenfonctiond’uncertaincritère.Considérezl’exemplesuivant:
UPDATEALIMENTS
SETEVALGRAISSE=CASE
WHENGRAISSE<1
THEN‘trèsallégé’
WHENGRAISSE<5
THEN‘allégé’
WHENGRAISSE<20
THEN‘modérémentallégé’
WHENGRAISSE<50
THEN‘trèsgras’
ELSE‘attaquecardiaque’
END;
CetteinstructionévaluelesconditionsWHENdansl’ordrejusqu’àcequel’unesoitvérifiée,aprèsquoielleignorelesautresconditions.
Le Tableau 8.2 du Chapitre 8 représente une table nutritionnellepour100grammesdediversaliments.UnebasededonnéesquicontiendraitcesinformationspeutrecevoirunecolonneEVALGRAISSEquidonneraitauconsommateurunaperçurapidedutauxdematièregraisseusedechaquealiment.Sivousappliquezl’instructionUPDATEàlatableALIMENTSduChapitre8,elleattribueraauxaspergesunevaleurtrèsallégéeetaupouletune valeur allégée.Les autres aliments seront classés dans la catégorie àhautrisque‘attaquecardiaque’.
EviterdesconditionsquigénèrentdeserreursL’expressionCASEpermetaussid’éviterdesexceptionsencontrôlantdesconditionssusceptiblesdeprovoquerdeserreurs.
Prenonspourexemplelesalairedecommerciaux.Lesentreprisesquipaientleurs commerciaux à la commission rémunèrent souvent leurs nouveauxemployés en leur versant un salaire qui anticipe sur l’évolution de leursrésultats.Dans l’exemplesuivant, lesnouveauxcommerciaux reçoiventunfixequidiminuelorsquelacommissionaugmente.
UPDATECOMP_VENTES
SETCOMP=COMMISSION+CASE
WHENCOMMISSION<>0
THENFIXE/COMMISSION
WHENCOMMISSION=0
THENFIXE
END;
Silacommissiond’uncommercialvautzéro(ildébute),lastructureutiliséedans l’exemplepermetd’éviteruneopérationdedivisionparzéro,cequiengendrerait une erreur. Si la commission du commercial n’est pas nulle,sonsalairetotalestégalàlacommissionpluslefixe,celui-ciétantcalculéproportionnellementàlacommission.
TouteslesexpressionsTHENd’unestructureCASEdoiventêtredumêmetype : toutes numériques, toutes des chaînes de caractères ou toutes desdates.Lerésultatdel’expressionCASEpossèdealorscemêmetype.
UtiliserCASEavecdesvaleursVous pouvez utiliser une forme plus compacte de l’expressionCASE sivous voulez comparer une valeur test à une série d’autres valeurs. Cettevariante se révèle utile au sein d’une instruction SELECT ou UPDATEdans le cas d’une table contenant un nombre limité de valeurs possiblesdansunecolonne,etquevousvoulezassocieruncertainrésultatàchacune
de ces valeurs. Si vous utilisez CASE de cette manière, l’expressionadopteralasyntaxesuivante:
CASEvaleurt
WHENvaleur1THENresultat1
WHENvaleur2THENresultat2
...
WHENvaleurnTHENresultatn
ELSEresultatx
END
Silavaleurtest(valeurt)estégaleàvaleur1, l’expressionprend lavaleur resultat1. Si valeurt n’est pas égale à valeur1, maiségale àvaleur2, l’expression prend la valeurresultat2. Le test sepoursuit jusqu’à ce qu’une correspondance soit trouvée. Si aucune desvaleursdecomparaisonn’est égaleà lavaleur test, l’expressionprend lavaleurresultatx.SilaclauseoptionnelleELSEn’estpasprésente,etsiaucunedescomparaisonsneréussit,l’expressionprendlavaleurnulle.
Pour comprendre comment fonctionne cette forme de CASE, prenonsl’exemple d’une table qui contient les noms et les grades de diversofficiers.Vousvoulezdresser la listedesnomsprécédésde l’abréviationcorrectedeleurgrade.L’instructionsuivanteeffectuecetravail:
SELECTCASEGRADE
WHEN‘général’THEN‘Gén.‘
WHEN‘colonel’THEN‘Col.‘
WHEN‘lieutenant-colonel’THEN‘Lt.Col.
‘
WHEN‘major’THEN‘Maj.‘
WHEN‘capitaine’THEN‘Capt.‘
WHEN‘premierlieutenant’THEN‘1erLt.‘
WHEN‘secondlieutenant’THEN2dLt.‘
ELSENULL
END;
NOM
FROMOFFICIERS;
Lerésultatpourraitseprésenterainsi:
Capt.Lestocade
Col.Durand
Gén.Napoléon
Maj.Désastre
Delabase
CommelegradedusoldatDelabasen’estpasmentionnédansl’expressionCASE, la clause ELSE laisse vide ce renseignement. Prenons un autreexemple.SupposezquelecapitaineLestocadesoitpromuaurangdemajor.Vous voulez doncmettre à jour la base de données OFFICIERS pour entenircompte.Lavariablenom_officierapourvaleur‘Lestocade’etlavariable nouveau_ grade contient un entier (4) qui correspond aunouveaugradedeLestocade,conformémentautableausuivant:
nouveau_grade Grade
1 général
2 colonel
3 lieutenant-colonel
4 major
5 capitaine
6 premierlieutenant
7 secondlieutenant
8 NULL
VouspouvezenregistrerlapromotionenutilisantlecodeSQLsuivant:
UPDATEOFFICIERS
SETGRADE=CASE:nouveau_grade
WHEN1THEN‘général’
WHEN2THEN‘colonel’
WHEN3THEN‘lieutenant-
colonel’
WHEN4THEN‘major’
WHEN5THEN‘capitaine’
WHEN6THEN‘premier
lieutenant’
WHEN7THEN‘secondlieutenant’
WHEN8THENNULL
END
WHERELAST_NAME=:nom_officier;
L’utilisation de CASE avec des valeurs peut aussi prendre une syntaxealternative:
CASE
WHENvaleurt=valeur1THENresultat1
WHENvaleurt=valeur2THENresultat2
...
WHENvaleurt=valeurnTHENresultatn
ELSEresultatx
END
Uncasparticulier:NULLIFLeschampsd’unebasededonnéescontiennentdesvaleursbiendéfinies,dumoins si elles sont déterminées. En général, si la valeur d’un champ estinconnue, il possède la valeur nulle (NULL). Sous SQL, vous pouvezutiliseruneexpressionCASEpourchanger lecontenud’unchampenunevaleurnulle.Lanullitéindiquequevousneconnaissezpluslavaleurdecechamp.
Supposez par exemple que vous êtes l’heureux propriétaire d’unecompagnie aérienne basée aux États-Unis qui propose des vols entre laCalifornieduSudetl’ÉtatdeWashington.Jusqu’àtoutrécemment,lesvolss’arrêtaient à l’aéroport international de San José pour faire le plein.
Malheureusement,onvousaretirél’autorisationd’atterriràSanJosé.Vousdevez désormais faire escale pour remplir vos avions de kérosène soit àl’aéroportdeSanFrancisco,soitàceluid’Oakland.Pourl’instant,vousnesavez pas quels sont les vols qui vont s’arrêter dans ces aéroports.Maisvoussavezqu’aucund’entreeuxnes’arrêteraplusàSanJosé.Votrebasededonnées VOLS contient des informations importantes sur chacune de vosroutesaériennes.Vousallezdoncmettreà jourcettebaseenysupprimanttoute référence à San José. L’exemple suivant propose une manière deprocéder:
UPDATEVOLS
SETESCALE_KEROSENE=CASE
WHENESCALE_KEROSENE
=‘San
José’
THENNULL
ELSEESCALE_KEROSENE
END;
Comme ce genre de situation se reproduit couramment, SQL propose unenotation abrégée pour effectuer ce type de travail. L’exemple précédentpourraitseprésenterainsienutilisantcettenotationabrégée:
UPDATEVOLS
SETESCALE_KEROSENE=NULLIF(ESCALE_KEROSENE,
‘San
José’);
Vouspouvezlirecetteexpressioncomme«mettreàjourlabasededonnéesVOLSenpassantlacolonneESCALE_KEROSENEànull,silavaleurdeESCALE_KEROSENEestSanJosé;autrement,nerienfaire».
NULLIFserévèleencorepluspratiquesivousconvertissezdesdonnéesque vous aviez accumulées pour les utiliser avec un langage deprogrammation standard tel que COBOL ou Fortran. Les langages deprogrammation standardne connaissent pas la valeurnull.C’est pourquoiils traduisent le concept d’« inconnu » à l’aide de valeurs spéciales. Parexemple, une valeur -1 peut représenter la valeur inconnue pour
SALAIRE et la chaîne de caractères « *** » peut figurer une valeurinconnueouindéterminabledeCODE_TRAVAIL.Sivousvouleztranscrireces états dans une base de données compatible SQL, vous devrez lesconvertir en valeurs nulles. L’exemple suivant effectue cette conversionpourlatableEMPLOYESoùsetrouventquelquessalairesdontlemontantestinconnu:
UPDATEEMPLOYES
SETSALAIRE=CASESALAIRE
WHEN-1THENNULL
ELSESALAIRE
END;
LaformeabrégéedeNULLIFestencoreplussimple:
UPDATEEMPLOYES
SETSALAIRE=NULLIF(SALAIRE,-1);
UnautrecasparticulierdeCASE:COALESCECOALESCE, comme NULLIF, est une forme abrégée particulière del’expressionCASE.Elle traiteune listedevaleursquipeuventêtreounepasêtrenulles.Voicicommentellefonctionne:
» Siuneseuledesvaleursdelalisten’estpasnulle,
l’expressionCOALESCEprendcettevaleur.
» Siplusd’unevaleurdelalisten’estpasnulle,
l’expressionretournelapremièrevaleurnonnulledecette
liste.
» Sitouteslesvaleursdelalistesontnulles,l’expression
prendlavaleurnulle.
UneexpressionCASEcorrespondantàcettedémarcheprendrait la formesuivante:
CASE
WHENvaleur1ISNOTNULL
THENvaleur1
WHENvaleur2ISNOTNULL
THENvaleur2
...
WHENvaleurnISNOTNULL
THENvaleurn
ELSENULL
END
LaformeabrégéeCOALESCEdonneracequisuit:
COALESCE(valeur1,valeur2....valeurn)
Vousutiliserezprobablementl’expressionCOALESCEaprèsavoireffectuéuneopérationOUTERJOIN(elleestabordéeauChapitre10).Danscecas,COALESCEpeutvouséviterdesaisirunegrandequantitédetexte.
Conversionsdetypesdedonnées(CAST)
LeChapitre 2 traite de tous les types de données que SQL reconnaît etsupporte.Dansl’idéal,chaquecolonned’unetabledebasededonnéesdoitposséderuntypededonnéesprécis.Cependant, iln’estpastoujoursaussisimpled’effectuer cette attribution.Supposonsqu’endéfinissant une tabledevotrebasededonnéesvousaffectiezàunecolonneuntypededonnéesconvenant parfaitement à l’état actuel de votre application. Par la suite,vous voulez étendre le champ de votre application, ou même écrire uneapplication totalement nouvelle qui utilise les données d’une manièredifférente. Cette nouvelle utilisation peut nécessiter un autre type dedonnéesqueceluiquiaétéchoisiàl’origine.
Vous pouvez aussi avoir besoin de comparer une colonne d’une tablepossédant un certain type avec une colonne d’un type différent dans uneautretable.Celaseproduiraparexemplesivousstockezdesdatessouslaformedechaînesdecaractèresdansunetable,etencoredesdates,maisauformat date-heure, dans une seconde table. Même si les deux colonnescontiennentdesinformationsdontlanatureestidentique(desdates),iln’estnormalementpaspossibledeprocéderàlacomparaisoncarleurstypessontdifférents.CetteincompatibilitéposeunproblèmedansSQL-86etSQL-89.Cependant,unesolutionsimpleexistedepuisSQL-92:l’expressionCAST.
L’expressionCASTconvertitlesdonnéesd’unetableoudesvariablesd’untype dans un autre.C’est ce que l’on appelle le transtypage.Après avoireffectué la conversion, vous pouvez effectuer l’opération ou lescomparaisonsquevoussouhaitez.
Bien entendu, l’utilisation de l’expressionCAST est soumise à certainesrestrictions.Vousnepouvezpasconvertirn’importequel typededonnéesdansunautre.Ladonnéeàconvertirdoitêtrecompatibleavecsonnouveautype.Parexemple,vouspouvezutiliserCASTpourconvertirunechaînedecaractèresdetypeCHAR(10)‘2007-04-26’entypeDATE.Cependant,vousne pouvez pas utiliser CAST pour convertir la chaîne de caractèresCHAR(10)‘rhinocéros’entypeDATE.Demême,iln’estpaspossibledetransformer un INTEGER en un type SMALLINT si la valeur deINTEGERdépasselavaleurmaximaleautoriséepourSMALLINT.
Vouspouvezconvertirunedonnéeden’importequeltypecaractèredansunautre(telquenumériqueoudate),àconditionquesavaleuradoptelaformelittéraledunouveautype.Demême,vouspouvezconvertirunedonnéed’untypequelconqueversuntypecaractèreàconditionquesavaleurprennelaformelittéraledutypeoriginal.
La liste suivante énumère les problèmes de conversion auxquels vouspouvezêtreconfronté:
» Untypenumériqueenn’importequeltype
numérique:sivousconvertissezversuntypedontla
partiedécimaleestmoinsprécise,lesystèmearrondiraou
tronqueralerésultat.
» Untypenumériqueexactenunintervalletelque
INTERVALDAYouINTERVALSECOND.
» UneDATEenunTIMESTAMP:lapartieheurede
TIMESTAMPserarempliedezéros.
» UnTIMEenTIMEdontlapartiedécimaledes
fractionsdesecondeestdifférente,ouenTIMESTAMP:
lapartiedatedeTIMESTAMPseraremplieavecladate
actuelle.
» UnTIMESTAMPenDATE,enTIMEouenTIMESTAMP
dontlaprécisiondelapartiefractionnelledes
secondesestdifférente.
» UnINTERVALmois-annéeenuntypenumérique
exactouenunINTERVALannée-moisdontlaprécision
duchamppréfixeestdifférente.
» UnINTERVALjour-heureenuntypenumériqueexact
ouenunautreINTERVALjour-heuredontlaprécision
duchamppréfixeestdifférente.
UtiliserCASTavecSQLSupposez que vous travaillez pour une société qui gère par ordinateur laliste complète de ses employés, qu’ils soient à temps plein ou à tempspartiel. Vous stockez la liste des employés à temps plein dans la tableEMPLOYES, et vous distinguez chacun d’entre eux par leur numéro deSécurité sociale que vous stockez sous la forme d’une chaîne du typeCHAR(9).VousdressezlalistedesemployésàtempspartieldansunetableTEMPS_PARTIEL.Mais,cettefois,leursnumérosdeSécuritésocialesontenregistrésau formatnumériqueINTEGER.Vousallezmaintenantgénérer
la listedespersonnesquiapparaissentdanscesdeux tables.VouspouvezfaireappelàCASTpoureffectuercettetâche:
SELECT*FROMEMPLOYES
WHEREEMPLOYES.NSS=
CAST(TEMPS_PARTIEL.NSSASINTEGER);
UtiliserCASTavecSQLetunlangagehôteCAST se révèle très utile pour gérer des types de données légaux dansSQL,maisquin’existentpasdanslelangagehôtequevousutilisez.Lalistesuivanteprésentequelquesexemplesdecestypesdedonnées:
» LestypesDECIMALetNUMERICdeSQLn’existentpasen
FortranetPascal.
» LestypesFLOATetREALdeSQLn’existentpasenCOBOL
standard.
» LetypeSQLDATETIMEn’existedansaucunautrelangage.
Supposons que vous utilisiez le Fortran ou le Pascal pour accéder à destablescontenantdescolonnesauformatDECIMAL(5,3).VoussouhaitezéviterleserreursgénéréeslorsdelaconversiondecesvaleursdansletypededonnéesREALduFortranetduPascal.Vouspouveztranstyperladonnéedans/depuis le typechaînedecaractèresdu langagehôte.Vous récupérezalorsunsalairenumérique‘898,37’souslaformed’unevaleurCHAR(10)‘0000898,37’. Pour ce faire, vous allez utiliser CAST afin detransformerletypededonnéesSQLDECIMAL(5,3)enunCHAR(10).Commencezparstockerl’identifiantEMPIDd’unemployédanslavariablehôte:emp_id_var:
SELECTCAST(SALAIREASCHAR(10))INTO
:salaire_var
FROMEMPLOYES
WHEREEMPID=:emp_id_var;
Vousutiliserezensuitelecodesuivantpourindiqueràl’applicationqu’elledoitexaminerlavaleurchaînedecaractèresquecontientsalaire_var,la transformer en une nouvelle valeur‘0000203,74’, puis lamettre àjourdanslabasededonnées:
UPDATEEMPLOYES
SETSALAIRE=CAST(:salaire_varASDECIMAL
(5,3))
WHEREEMPID=:emp_id_var;
Ilestdifficiledegérerdeschaînesdecaractèrestellesque‘000198,37’en Fortran ou Pascal. Mais vous pouvez écrire un ensemble de sous-programmesquieffectueront lesmanipulationsnécessaires. Il seraensuitepossiblederécupéreretmettreàjourn’importequelledonnéeSQLdepuisunlangagehôtequelconque.
L’idéegénéraleestqueCASTconvientmieuxàlaconversiondetypesdedonnéesentreunhôteetunebasequ’autranstypageàl’intérieurdelabasededonnéeselle-même.
LesexpressionsvaleurdeligneDans les standardsSQLd’origine, telsqueSQL-86etSQL-89, laplupartdesopérationstraitentuneseulevaleurouuneseulecolonnedansuneligned’une table. Pour opérer sur plusieurs valeurs, vous devez construire desexpressions complexes en utilisant des connecteurs logiques (ils sontabordésauChapitre10).
DepuisSQL-92,vouspouvezutiliserdesexpressionsvaleurdeligne.Cesexpressionspermettentdemanipulerunelistedevaleursoudecolonnes,etnon plus simplement une seule valeur ou une seule colonne. Elles seprésententsous laformed’uneséried’expressionsdevaleurséparéespardesvirgulesetdélimitéespardesparenthèses.Vouspouvezopérersurunelignetoutentièreouseulementsurunepartiedecetteligne.
Le Chapitre 6 explique comment utiliser l’instruction INSERT pourajouterunenouvelleligneàunetable.Poursefaire,l’instructionutiliseune
expressionvaleurdeligne.Parexemple:
INSERTINTOALIMENTS
(NOM,CALORIES,PROTEINES,GRAISSE,
HYDRATECARBONE)
VALUES
(‘Fromage,cheddar’,398,25,32.2,2.1)
Dans cet exemple, (‘Fromage, cheddar’, 398, 25, 32.2,2.1)estuneexpressionvaleurdeligne.Sivousutilisezdecettemanièreune telle expression dans une instructionINSERT, elle peut contenir desvaleursnullesoupardéfaut (unevaleurpardéfautest celle queprendunecolonnedela tableenl’absencedetoute information).Lalignesuivanteestuneexpressionvaleurdeligneautorisée:
(‘Fromage,cheddar’,398,NULL,32.2,DEFAULT)
VouspouvezajoutersimultanémentplusieurslignesàunetableenutilisantdemultiplesvaleursdansuneclauseVALUES,commesuit:
INSERTINTOALIMENTS
(NOM,CALORIES,PROTEINES,GRAISSE,
HYDRATECARBONE)
VALUES
(‘Lait’,14,1.2,0.2,2.5)
(‘Margarine’,720,0.6,81.0,0.4)
(‘Moutarde’,75,4.7,4.4,6.4)
(‘Spaghetti’,148,5.0,0.5,30.1)
Il est aussi possible d’utiliser des expressions valeur de ligne poursimplifierl’écrituredecomparaisons.Supposezquevousavezdeuxtablesde valeurs nutritionnelles, l’une en français et l’autre en espagnol. Vousrecherchezleslignesdanslatableenfrançaisquicorrespondentexactementaux lignes de la table en espagnol. Sans les expressions valeur de ligne,vousdevriezécrirequelquechosecomme:
SELECT*FROMALIMENTS
WHEREALIMENTS.CALORIES=COMIDA.CALORIA
ANDALIMENTS.PROTEINES=COMIDA.PROTEINA
ANDALIMENTS.GRAISSE=COMIDA.GORDO
ANDALIMENTS.HYDRATECARBO=
COMIDA.CARBOHIDRATO;
Lesexpressionsvaleurdelignevouspermettentd’écrirelemêmecodedelamanièresuivante:
SELECT*FROMALIMENTS
WHERE(ALIMENTS.CALORIES,ALIMENTS.PROTEINES,
ALI-
MENTS.GRAISSE,
ALIMENTS.HYDRATECARBO)
=
(COMIDA.CALORIA,COMIDA.PROTEINA,
COMIDA.GORDO,
COMIDA.CARBOHIDRATO);
Danscetexemple,legaindesaisien’estpasénorme.Maisvouspourriezlasimplifierdavantagesivouscompariezplusieurscolonnes.Sileprofitn’estquemarginal,autantutiliserlasyntaxedéveloppée,carelleestplusfacileàlire(etdoncàcorrigeroumodifierlecaséchéant).
Unautreavantagede l’expressionvaleurde lignesursonéquivalentcodéestqu’elleestplusrapide.Enprincipe,uneimplémentation«intelligente»devraitêtrecapabled’analyserlaversioncodéeetdelatransformerenuneversionvaleurde ligne.Mais,enpratique,c’estuneopérationdifficileetdélicatequ’aucunSGDBactuelnesaiteffectuer.
U
Chapitre10Isolerlesdonnéesdontvousavezbesoin
DANSCECHAPITRE:
» Spécifierlestablesaveclesquellesvousvouleztravailler.
» Isolerleslignesdignesd’intérêt.
» ConstruiredesclausesWHEREefficaces.
» Gérerlesvaleursnulles.
» Construiredesexpressionscomposéesavecdesconnecteurslogiques.
» Regrouperlesrésultatsd’unerequêteparcolonne.
» Ordonnerlerésultatd’unerequête.
» Opérersurdeslignesrelatives.
nsystèmedegestiondebasededonnéesadeuxfonctionsprincipales:stocker les données et y donner facilement accès. Enregistrer lesdonnéesn’estpascompliqué.Unearmoireàfichierspeutfairelamême
chose.Touteladifficultérésidedansl’accèsauxdonnées.Pourquecelles-cisoientutiles,vousdevezêtrecapabledeséparerlepetitnombred’entreellesquivousintéressedel’énormevolumededonnéesdontvousnevoulezpas.
SQL vous permet d’utiliser quelques caractéristiques de la donnée elle-mêmepourdéterminersiunecertaineligned’unetableestd’unquelconqueintérêt pour vous. Les instructions SELECT, DELETE et UPDATEindiquentaumoteurdelabase(lapartieduSGBDquiagitsurlesdonnées)quellelignevousallezsélectionner,supprimeroumodifier.Ilestpossible
d’ajouterdesclausesmodificatricesauxinstructionsSELECT,DELETEetUPDATEafind’affinerlarecherche.
ClausesmodificatricesLes clauses modificatrices disponibles en SQL sont
FROM, WHERE, HAVING, GROUP BY et ORDER BY. La clauseFROMindiqueaumoteurdebasededonnéeslaoulestablessurlesquellesvous voulez travailler. Les clauses WHERE et HAVING spécifient unecaractéristiquedeladonnéequipermetdedéciders’ilfautounoninclureuneligneparticulièredansl’opérationcourante.LesclausesGROUPBYetORDER BY précisent comment organiser les lignes récupérées. LeTableau10.1vousprésenteunrécapitulatif.
TABLEAU10.1Clausesmodificatricesetfonctions.
Clause
modificatrice
Fonction
FROM Spécifiedequelletablelesdonnéessontextraites.
WHERE Filtreleslignesquinerépondentpasauxcritèresde
recherche.
GROUPBY Sépareleslignesregroupéesselonlesvaleursdes
colonnesderegroupement.
HAVING Filtrelesgroupesquinecorrespondentpasaux
critèresderecherche.
ORDERBY Trielesrésultatsproduitsparlesclausesprécédentes
pourdonnerlerésultatfinal.
Si vous utilisez simultanément plusieurs de ces clauses, elles doiventapparaîtredansl’ordresuivant:
SELECTliste_colonnes
FROMliste_tables
[WHEREcriteres_recherche]
[GROUPBYcolonnes_groupe]
[HAVINGcriteres_recherche]
[ORDERBYcriteres_tri]
Voiciunrésumédurôledecesclauses:
» LaclauseWHEREestunfiltrequilaissepasserleslignes
quicorrespondentauxcritèresderechercheetrejetteles
autres.
» LaclauseGROUPBYordonneleslignesquelaclause
WHERElaissepasserenfonctiondesvaleursprésentes
danslescolonnesderegroupement.
» LaclauseHAVINGestunautrefiltrequinelaissepasser
quelesgroupesproduitsparlaclauseGROUPBY
répondantaucritèrederecherche,lesautresétantrejetés.
» LaclauseORDERBYtriecequiresteunefoisqueles
clausesprécédentesonttraitélatable.
Commelaprésencedecrochets([])l’indique,lesclausesWHERE,GROUPBY,HAVINGetORDERBYsontoptionnelles.
SQLévaluecesclausesdansl’ordreFROM,WHERE,GROUPBY,HAVINGet enfinSELECT.Elles sont traitées commedans un« pipeline », ce quisignifie que chaque clause reçoit le résultat de la clause précédente etproduit un résultat pour la clause suivante. En notation fonctionnelle, cetordred’évaluationestlesuivant:
SELECT(HAVING(GROUPBY(WHERE(FROM...)))
ORDERBY intervient aprèsSELECT, ce qui explique pourquoiORDERBYnepeut référencerquedescolonnesprésentesdans la listeSELECT.ORDERBYnepeutpasutiliserd’autrescolonnesprovenantdelaoudestablesFROM.
ClausesFROMIlestfaciledecomprendrelaclauseFROMsivousn’utilisezqu’uneseuletable,commedansl’exemplesuivant:
SELECT*FROMVENTES;
CetteinstructionretournetouteslesdonnéesdetoutesleslignesdechaquecolonnedelatableVENTES.Cependant,vouspouvezspécifierplusd’unetabledansuneclauseFROM.Considérezl’exemplesuivant:
SELECT*
FROMCLIENTS,VENTES;
Cette instruction génère une table virtuelle qui associe les données de latableCLIENTSaveclesdonnéesdelatableVENTES.ChaquelignedelatableCLIENTSestcombinéeavecchaquelignedelatableVENTESpourformerlanouvelletable.Cettedernièrecontientdoncunnombredeligneségalàceluide la tableCLIENTSmultipliépar lenombrede lignesde latableVENTES.SiCLIENTSpossèdedixlignesetqueVENTESenacent,alorslanouvelletablevirtuelleencontientmille...
Cette opération est appeléeproduit cartésien de deux tables sources. Leproduitcartésienestenfaituntypedejointure.LesopérationsdejointuresonttraitéesendétailauChapitre11.
Dans la plupart des applications, les lignes obtenues à l’issue du produitcartésiendedeuxtablessontgénéralementdépourvuesdesens.Danslecasde la table virtuelle formée à partir des tables CLIENTS et VENTES,seules les lignes où leCLIENT_ IDde la tableCLIENTS correspond auCLIENT_ID de la table VENTES sont dignes d’intérêt. Vous pouvezéliminertoutleresteenutilisantuneclauseWHERE.
LesclausesWHEREDanscelivre, j’aidéjàutilisédenombreusesfois laclauseWHEREsansvraiment la présenter, car sa signification et son utilisation semblentévidentes. Une instruction effectue une opération (comme SELECT,DELETEouUPDATE)uniquementsurleslignesquivérifientlaconditionexpriméeparlaclauseWHERE.Lasyntaxedecetteclauseestlasuivante:
SELECTliste_colonnes
FROMnom_table
WHEREcondition;
DELETEFROMnom_table
WHEREcondition;
UPDATEnom_table
SETcolonne1=valeur1,colonne2=valeur2,
...co-
lonnen=valeurn
WHEREcondition;
La condition exprimée par la clause WHERE peut être simple ouarbitrairement complexe. À l’aide des connecteurs logiquesAND,OR etNOT (ils sont traités plus loin dans ce chapitre), il est possible decombinerplusieursconditionspourencréerunenouvelle.
LesinstructionssuivantesvousprésententquelquesutilisationsdelaclauseWHERE:
WHERECLIENTS.CLIENT_ID=VENTES.CLIENT_ID
WHEREALIMENTS.CALORIES=COMIDA.CALORIA
WHEREALIMENTS.CALORIES<219
WHEREALIMENTS.CALORIES>3+valeur_base
WHEREALIMENTS.CALORIES<219AND
ALIMENTS.PROTEINES>
27.4
Les conditions que la clause WHERE exprime sont également appeléesprédicats.Unprédicatestuneexpressionquiexprimeunfaitconcernantlesvaleurs.
Par exemple, le prédicat ALIMENTS. CALORIES < 219 est vrai si lavaleur de la ligne courante de la colonne ALIMENTS. CALORIES eststrictement inférieure à 219. Si cette assertion est vraie, la condition estremplie.Uneassertionpeutêtresoitvraie,soit fausse,soit inconnue.Elleest inconnue si un ou plusieurs éléments dans cette assertion sont nuls(c’est-à-dire inconnus, indéfinis, indéterminables, etc.). Les prédicats decomparaison (=, <, >, <>, <= et <=) sont les plus utilisés,mais SQL encomported’autresqui vouspermettent d’isoler demanièrebeaucoupplusprécise les données que vous recherchez. La liste suivante répertorie lesprédicatsservantàfiltrerlesdonnées:
» Prédicatsdecomparaison
» BETWEEN
» IN[NOTIN]
» LIKE[NOTLIKE]
» NULL
» ALL,SOME,ANY
» EXISTS
» UNIQUE
» OVERLAPS
» MATCH
» SIMILAR
» DISTINCT
Lesprédicatsdecomparaison
Les exemples de la section précédente sont des usages typiques desprédicats de comparaison : vous y comparez une valeur à une autre.L’opération (SELECT, UPDATE, DELETE, etc.) est appliquée à chaqueligne pour laquelle cette comparaison est évaluée comme étant vraie(TRUE), autrement dit pour laquelle la clauseWHERE est satisfaite. Leslignes pour lesquelles la comparaison renvoie FALSE sont éliminées.Considérezparexemplel’instructionSQLsuivante:
SELECT*FROMALIMENTS
WHERECALORIES<219;
Cette instruction affiche toutes les lignes de la table ALIMENTS pourlesquelleslavaleurdelacolonneCALORIESestinférieureà219.
LeTableau10.2présentesixprédicatsdecomparaison:
BETWEENIlarrivequevoussouhaitiezreteniruneligneuniquementsilavaleurd’unede ses colonnes est comprise dans une certaine plage. L’utilisation deprédicatsdecomparaisonvouspermetd’effectuercetypedesélection.Parexemple,vouspouvezformuleruneclauseWHEREservantàsélectionnertoutes les lignes de la table ALIMENTS dans lesquelles la valeur de lacolonneCALORIESestsupérieureà100etinférieureà300:
TABLEAU10.2PrédicatsdecomparaisonSQL.
Comparaison Symbole
Egalà =
Différentde <>
Inférieurà <
Inférieurouégalà <=
Supérieurà >
Supérieurouégalà >=
WHEREALIMENTS.CALORIES>100AND
ALIMENTS.CALORIES<300
Cettecomparaisonn’inclutpas lesalimentsdont lavaleurdeCALORIESvautexactement100ou300.Pourinclurecesvaleurslimites,vouspouvezécrirel’instructionci-dessous:
WHEREALIMENTS.CALORIES>=100AND
ALIMENTS.CALORIES<=300
UneautremanièredespécifieruneplagequicomprendcesbornesconsisteàutiliserleprédicatBETWEENcommesuit:
WHEREALIMENTS.CALORIESBETWEEN100AND300
Cetteclauseestfonctionnellementidentiqueàcelledel’exempleprécédent,quiutilisedesprédicatsdecomparaison.Commevouspouvezleconstater,cette formulation est plus efficace et un peu plus intuitive que celle quiutilisedeuxprédicatsdecomparaisonreliésparleconnecteurlogiqueAND.
Le mot clé BETWEEN peut prêter à confusion, car il n’indique pasexplicitementsilaclausecomprendlesvaleurslimites.Enfait,laréponseestoui.Deplus, aucunpetitoiseaunevavenir seposer survotreépaulepourvousrappelerque lepremier termede lacomparaisondoitêtreégalouinférieurausecond.Parexemple,siALIMENTS.CALORIEScontientunevaleurde200,laclausesuivanteestvalidée:
WHEREALIMENTS.CALORIESBETWEEN100AND300
Cependant,laclauseci-dessous,quisemblepourtantéquivaloiràl’exempleprécédent,fourniralerésultatinverse:
WHEREALIMENTS.CALORIESBETWEEN300AND100
Si vous utilisez BETWEEN, vous devez pouvoir garantir que le premiertermedevotrecomparaisonesttoujourségalouinférieurausecond.
Vous pouvez utiliser le prédicat BETWEEN avec les types de donnéescaractère,bit,date/heureainsiqu’aveclestypesnumériques.Vouspourriezrencontrerquelquechosecommececi:
SELECTPRENOM,NOM
FROMCLIENTS
WHERECLIENTS.NOMBETWEEN‘A’AND‘Mzzz’;
Cet exemple retourne tous les clients dont le nom est dans la premièremoitiédel’alphabet(àmoinsquenecommerciezavecM.Mzzzzza).
INetNOTINLes prédicats IN et NOT IN permettent de vérifier si des valeursspécifiques (telles que OR, WA et ID) appartiennent à des ensemblesparticuliers de valeurs (en l’occurrence, des États des États-Unis). Parexemple,unedevostablescontientlalistedesfournisseursaméricainsdeconsommables que votre société achète régulièrement. Vous voulezconnaîtrelesnumérosdetéléphonedesfournisseursquisetrouventdansleNord-Ouest Pacifique. Vous pouvez obtenir ces numéros en utilisant desprédicatsdecomparaisoncommesuit:
SELECTSociete,Telephone
FROMFOURNISSEURS
WHEREEtat=‘OR’OREtat=‘WA’OrEtat=
‘ID’;
Vous pouvez également faire appel au prédicat IN pour réaliser lamêmetâche:
SELECTSociete,Telephone
FROMFOURNISSEURS
WHEREEtatIN(‘OR’,‘WA’,‘ID’);
Cette formulationestunpeuplus compacteque laprécédente.LaversionNOTIN de ce prédicat fonctionne de la même manière. Supposez quevouspossédiezdes succursales enCalifornie, enArizona et auNouveau-Mexique, et que pour éviter de payer des taxes vous cherchiez à vous
adresser à tous les fournisseurs sauf ceux qui résident dans ces États.Utilisezalorslaconstructionsuivante:
SELECTSociete,Telephone
FROMFOURNISSEURS
WHEREEtatNOTIN(‘CA’,‘AZ’,‘NM’);
UtiliserainsilemotcléINestunpeupluséconomique.Cequin’estpasforcémentensoiunavantagedécisif.Vouspourrieztoutaussibienobtenirlemêmerésultatenutilisantlesprédicatsdecomparaison,commedanslepremierexempledecettesection.
Mêmesil’utilisationdeINnereprésentepasuneéconomieconsidérable,elleoffreunautreavantageparrapportauxprédicatsdecomparaison.VotreSGBD implémente probablement ces deuxméthodes différemment.De cefait,l’uned’entreellespeuts’exécuterbienplusrapidementquel’autresurvotre système. Bien entendu, vous allez opter pour la plus rapide.D’ailleurs, un SGBD doté d’un bon optimisateur fera automatiquement lechoixdel’efficacité,sanstenircomptedelasyntaxequevousaurezutiliséedansvotrerequête.UntestdecomparaisondesperformancesvousdonnerauneidéesurlamanièredetravaillerdevotreSGBD.Sivousremarquezunedifférence significative entre les temps d’exécution des deux méthodes,c’est que la qualité de l’optimisateur de votreSGBDpeut être remise enquestion.
Lemot cléIN se révèle également utile dans un autre cas. SiIN faitpartie d’une sous-requête, il vous permet d’extraire des informationsprovenantdedeuxtablesafind’obtenirdesrésultatsquevousnepourriezpasdériverd’uneseuletable.LeChapitre11revientplusendétailsurlessous-requêtes.Cependant,l’exemplesuivantmontrecommentutiliserlemotcléINdansunesous-requête.
SupposezquevousvouliezaffichertouslesnomsdesclientsquiontachetéleproduitF-117Adanslestrentederniersjours.Lesnomsdesclientssontstockés dans la table CLIENTS et les transactions commerciales sontmémorisées dans la table TRANSACTIONS. Vous pouvez utiliser larequêtesuivante:
SELECTNOM,PRENOM
FROMCLIENTS
WHERECLIENT_IDIN
(SELECTCLIENT_ID
FROMTRANSACTIONS
WHEREPRODUIT_ID=‘F-117A’
ANDDATE_TRANS>=(DATE_COURANTE-30));
LeSELECT interne qui porte sur la table TRANSACTIONS est inclusdansleSELECTexternequitraitelatableCLIENTS.LeSELECTinterneretourne les numéros CLIENT_ID de tous les clients qui ont acheté leproduitF-117Adurantlestrentederniersjours.LeSELECTexterneaffichelesnomsetprénomsdesclientsdont leCLIENT_IDaétérécupérépar leSELECTinterne.
LIKEetNOTLIKEVouspouvezutiliser leprédicatLIKEpour procéder à une comparaisonpartielle de deux chaînes de caractère. Les comparaisons partielles sontutilessivousneconnaissezpaslaformeexactedecequevousrecherchez.Vous pouvez aussi utiliser des comparaisons partielles pour récupérerplusieurs lignes qui contiennent des chaînes similaires dans une colonnedonnée.
SQL utilise deux caractères de substitution. Le signe pourcentage( %)remplace n’importe quelle chaîne de caractères qui comprend zéro ouplusieurscaractères.Letraitdesoulignement(_)sesubstitueàuncaractèreunique quelconque. Le Tableau 10.3 contient quelques exemplesd’utilisationdeLIKE.
LeprédicatNOTLIKE retourne toutes les lignesquinevérifientpas lacomparaisonpartielle,commedans:
WHERETELEPHONENOTLIKE‘503%’
Cet exemple retourne toutes les lignes de la table dont le numéro detéléphonecommenceparquelquechosededifférentde503.
TABLEAU10.3LeprédicatLIKEdeSQL.
Instruction Valeurretournée
WHEREWORDLIKE‘intern%’ interne
international
internet
WHEREWORDLIKE‘%paci%’ océanpacifique
mouvementpacifique
WHEREWORDLIKE‘t_p_’ tape
tapi
tipi
type
Ilpeutarriverquevousrecherchiezunechaînequicontienneelle-mêmelesignepourcentageouun trait de soulignement.Dans ce cas,vousvoudrezque SQL interprète le signe pourcentage comme le signe « % » et noncomme un caractère de substitution. Pour ce faire, vous devrez saisir uncaractère d’échappement juste avant le signe en question. Vous pouvezutilisern’im
porte quel caractère comme caractère d’échappement du moment qu’iln’apparaîtpasdanslachaînequevoustestez.Parexemple:
SELECTCITATION
FROMBARTLETTS
WHERECITATIONLIKE‘20#%’
ESCAPE‘#’;
Lecaractère«%»estpréfixédusigned’échappement«#»,sibienquel’instructioninterprètecesymbolecommelesigne«%»etnoncommelecaractèredesubstitution.Vouspouvez traiter le traitdesoulignementet lecaractère d’échappement lui-même de lamêmemanière.Ainsi la requêteprécédentepourraitrenvoyerlacitationsuivante:
20%descommerciauxproduisent80%desrésultats
Elleretourneraitaussi:
20%
SIMILARLeprédicatSIMILAR(introduitdansSQL:1999)permetaussid’effectuerdescomparaisonspartielles,maisilestpluspuissantqueLIKE.GrâceauprédicatSIMILAR,vouspouvezcomparerunechaînedecaractèresàuneexpressionrégulière.Supposezparexemplequevousdeviezeffectuerunerecherche dans la colonne SYSTEME_EXPLOITATION d’une table decompatibilité logicielleà la recherched’unecompatibilitéavecMicrosoftWindows.VouspourriezconstruireuneclauseWHEREcommesuit:
WHERESYSTEME_EXPLOITATIONSIMILARTO
‘(‘Windows‘(3.1|95|98|MilleniumEdi-
tion|CE|NT|2000|XP))’;
Ce prédicat retourne toutes les lignes qui contiennent l’un des systèmesd’exploitationdeMicrosoft.
NULLLe prédicatNULL retourne toutes les lignes où la valeur de la colonnesélectionnéeestnulle.DanslatableALIMENTSduChapitre8,lacolonneHYDRATECARBONE de plusieurs lignes contient une valeur nulle. Vouspouvezrécupérerlenomdesalimentscorrespondantsenutilisant:
SELECT(ALIMENT)
FROMALIMENTS
WHEREHYDRATECARBONEISNULL;
Cetterequêteretournelesvaleurssuivantes:
Boeuf,hamburgerallégé
Poulet,allégé
Opossum,rôti
Porc,jambon
Commevousvousyattendez, lemotcléNOT inverse le résultat, commedansl’exemplesuivant:
SELECT(ALIMENT)
FROMALIMENTS
WHEREHYDRATECARBONEISNOTNULL;
Cetterequêterenvoietoutesleslignesdelatable,àl’exceptiondesquatreretournéesparl’exempleprécédent.
L’instruction HYDRATECARBONE IS NULL n’est pas la même queHYDRATECARBONE=NULL.Supposezquedanslalignecourantedelatable ALIMENTS les champs HYDRATECARBONE et PROTEINESsoientnuls.Vouspourrezenconclurecequisuit:
» HYDRATECARBONEISNULLestvrai.
» PROTEINESISNULLestvrai.
» HYDRATECARBONEISNULLANDPROTEINESISNULL
estvrai.
» HYDRATECARBONE=PROTEINESestinconnu.
» HYDRATECARBONE=NULLestuneexpressionillégale.
L’utilisationdumotcléNULLdansunecomparaisonn’aaucunsens,car,danscecas,lerésultatdelacomparaisonesttoujoursinconnu.
PourquoiHYDRATECARBONE=PROTEINES est-il inconnu,même siHYDRATECARBONEetPROTEINESont lamême valeur nulle ? ParcequeNULLsignifiesimplement« jenesaispas».SivousnesavezpasàquoicorrespondentHYDRATECARBONEetPROTEINES,vousnepouvezpas savoir si ces deux valeurs sont identiques. Peut-être que
HYDRATECARBONE vaut 37 et PROTEINES 14, ou peut-être queHYDRATECARBONEetPROTEINESvalentchacune93.Sivousnesavezpascequesontcesdeuxvaleurs,vousn’avezaucunmoyendedéterminersiellessontounonégales.
ALL,SOME,ANYIl y a des centaines d’années, le philosophe grec Aristote a formulé unsystème de logique qui est devenu le fondement d’une bonne partie de lapensée occidentale. L’essence de cette logique repose sur l’énoncé deprémissesquevoussavez(ousupposez)êtrevraies,prémissesauxquellesvousappliquezdesopérationsvalidespourarriveràdenouvellesvérités.Voiciunexempledecetteprocédure:
Prédicat1:TouslesGrecssonthumains.
Prédicat2:Tousleshumainssontmortels.
Conclusion:TouslesGrecssontmortels.
Autreexemple:
Prédicat1:CertainsGrecssontdesfemmes.
Prédicat2:Touteslesfemmessontdesêtreshumains.
Conclusion:CertainsGrecssontdesêtreshumains.
Lemêmeraisonnementlogiquepourraitêtreformuléd’unemanièreunpeudifférente:
SiquelquesGrecssontdesfemmes,etquetoutesles
femmessontdesêtreshumains,alorsquelquesGrecs
sontdesêtreshumains.
LepremierexempleutiliselequantificateuruniverselALL(tous)danslesdeuxprémisses,cequivouspermetdeprocéderàunedéductiongénéralesur les Grecs dans la conclusion. Le deuxième exemple utilise le
quantificateur existentiel SOME (certains, quelques) dans la premièreprémisse, ce qui vous permet de procéder à une déduction sur un certainnombredeGrecsdans laconclusion.Le troisièmeexemple (qui s’écriraitenanglaisifanyGreeks...)utiliseunquantificateurexistentiel(ANY)quiestunsynonymedeSOMEpourarriveràlamêmeconclusionqueledeuxièmeexemple.VoyonscommentANYetSOMEsont traités en SQL en passantdirectementdelaGrèceauxÉtats-Unis.
Prenons l’exemple de statistiques de base-ball. Le base-ball est un sporttrès éprouvant, en particulier pour les lanceurs.Un lanceur doit lancer laballe entre90 et 150 fois lorsd’unepartie, cequi est très fatigant.C’estpourquoilelanceurestsouventremplacéparunautrejoueuravantlafindelapartie.Tenirlerôledelanceurpendanttouteunepartieestunvéritableexploit,quelquesoitlerésultatdumatch.
Supposez que vous conserviez toutes les grandes parties dans lesquellestouslesgrandslanceursontjoué.Dansunetable,vousallezdresserlalistedes lanceurs de la Ligue américaine, et dans une autre table celle deslanceurs de la Ligue nationale. Chaque table contient pour un joueur sonnom,sonprénometlenombredematchesentiersauxquelsilaparticipé.
Supposons maintenant que vous souteniez la théorie selon laquelle leslanceursdelaLigueaméricainejouentdespartiesentièresplussouventqueceux de la Ligue nationale. Pour vérifier cette hypothèse, vous allezformulerlarequêtesuivante:
SELECTNOM,PRENOM
FROMLIGUE_AMERICAINE
WHEREPARTIES_COMPLETES>ALL
(SELECTPARTIES_COMPLETES
FROMLIGUE_NATIONALE);
Lasous-requête(SELECTinterne)retourneunelistequiindiquelenombrede parties complètes auxquelles a participé chaque lanceur de la Liguenationale. La requête externe retourne ensuite le nom et le prénom deslanceurs de la Ligue américaine qui ont participé à plus de partiescomplètesquetous(ALL)leslanceursdelaLiguenationale.
Regardezmaintenantl’instructionsuivante:
SELECTNOM,PRENOM
FROMLIGUE_AMERICAINE
WHEREPARTIES_COMPLETES>ANY
(SELECTPARTIES_COMPLETES
FROMLIGUE_NATIONALE);
Dans ce cas, vous utilisez le quantificateur existentiel ANY, et non lequantificateuruniverselALL.Lasous-requête(interne)estidentiqueàcellede l’exemple précédent. Elle retourne à nouveau la liste de toutes lesparties complètes auxquelles ont participé les lanceurs de la Liguenationale. La requête externe retourne le nom et le prénom de tous leslanceursdelaLigueaméricainequiontparticipéàplusdematchesentiersquen’importequellanceurdelaLiguenationale.Commevouspouvezêtrevirtuellementcertainqu’aumoinsundeslanceursdelaLiguenationalen’apasparticipéàunmatchentier,lerésultatcomprendprobablementtousleslanceurs de la Ligue américaine qui ont réalisé au moins une partiecomplète.
Si vous remplacez le mot cléANYpar le mot clé équivalent SOME, lerésultat est identique. Si l’assertion « au moins un lanceur de la Liguenationalen’apasparticipéàunepartiecomplète»estvérifiée, ildevientexactdedire«quelqueslanceursdelaLiguenationalen’ontpasparticipéàunepartiecomplète».
EXISTSVous pouvez utiliser le prédicat EXISTS avec une sous-requête pourdéterminersicettedernière retourneounondes lignes.Si lasous-requêteretourne au moins une ligne, c’est que le résultat vérifie la conditionEXISTS.Larequêteexterneestalorsexécutée.Parexemple:
SELECTNOM,PRENOM
FROMCLIENTS
WHEREEXISTS
(SELECTDISTINCTCLIENT_ID
FROMVENTES
WHEREVENTES.CLIENT_ID=
CLIENTS.CLIENT_ID);
La table VENTES contient un enregistrement de toutes les ventes de lasociété.On y trouve leCLIENT_ID de chaque client ayant effectué unachat ainsi que d’autres informations pertinentes. La table CLIENTScontientlenometleprénomdechaqueclient,maisaucuneinformationsurdestransactionsspécifiques.
La sous-requête de l’exemple précédent renvoie une ligne pour chaqueclientquiaeffectuéaumoinsunachat.Larequêteexterneretournelenometle prénomdes clients qui ont effectuédes achats référencésdans la tableVENTES.
EXISTS est l’équivalent d’une comparaison de COUNT avec zéro,commelemontrelarequêtesuivante:
SELECTNOM,PRENOM
FROMCLIENTS
WHERE0<>
(SELECTCOUNT(*)
FROMVENTES
WHEREVENTES.CLIENT_ID=CLIENTS.CLIENT_ID);
PourchaquelignequicontientunCLIENT_IDégalàunCLIENT_IDde la table CLIENTS, cette instruction renvoie les colonnes NOM etPRENOMdelatableCLIENTS.End’autrestermes,elleaffichelenomduclientquiaeffectuél’achatpourchaquetransactiondelatableVENTES.
UNIQUEToutcommepourEXISTS,vouspouvezutiliserleprédicatUNIQUEavecunesous-requête.Maisalorsqu’EXISTSestévaluécommeétantvraisiet seulement si la sous-requête renvoie au moins une ligne, le prédicatUNIQUEestvalidésietseulementsilasous-requêteneretournepasdeuxlignesidentiques.Autrementdit,UNIQUEn’estvraiquequand toutes leslignesfourniesparlasous-requêtesontuniques.
Prenonsl’exemplesuivant:
SELECTNOM,PRENOM
FROMCLIENTS
WHEREUNIQUE
(SELECTCLIENT_IDFROMVENTES
WHEREVENTES.CLIENT_ID=CLIENTS.CLIENT_ID)
;
CetteinstructionretrouvelesnomsdetouslesclientspourlesquelslatableVENTESnerecensequ’uneseuletransaction.Notezbienquedeuxvaleursnulles ne sont pas considérées comme étant égales et sont donc uniques.Lorsque lemot cléUNIQUE est appliqué à une table de résultat qui necontient que deux lignes nulles, le prédicatUNIQUE est évalué commeayantlavaleurTrue(vrai).
DISTINCTLeprédicatDISTINCT est comparable àUNIQUE, si ce n’est qu’il netraitepaslesvaleursnullesdelamêmemanière.Sitouteslesvaleursdelatable résultat sont UNIQUE, alors elles sont DISTINCT les unes desautres. Cependant, le prédicatDISTINCT n’est pas vérifié quand il estappliqué à une table résultat qui ne contient quedeux lignesnulles.Deuxvaleursnullesnesontpasconsidéréescommeétantdistinctes,toutenétantquandmêmeuniques.
Cela peut sembler paradoxal, mais il n’y a aucune raison à cela. Danscertainscas,vousvouleztraiterdeuxvaleursnullescommeétantdifférentesl’une de l’autre. Dans d’autres circonstances, vous avez besoin de lesplacerdansunmêmesac,etdoncdelesconsidérercommeidentiques.Avecla première situation, vous utiliserez le prédicat UNIQUE ; dans laseconde,vousferezappelauprédicatDISTINCT.
OVERLAPSLeprédicatOVERLAPSpermetdedéterminersideuxintervallesdetempssechevauchent.Ilestutilepouréviterparexempledesconflitsd’emploidu
temps. Si deux intervalles se chevauchent, le prédicat est évalué commeétantvrai.Sinon,iln’estpasvalidé.
Vous pouvez spécifier un intervalle de deuxmanières : soit à l’aide d’unpointdedépartetd’unpointfinal,soitàpartird’unpointdedépartetd’unedurée.Voiciquelquesexemples:
(TIME‘2:55:00’,INTERVAL‘1’HOUR)
OVERLAPS
(TIME‘3:30:00’,INTERVAL‘2’HOUR)
L’exempleprécédent renvoieTrue, car3heures30estmoinsd’uneheureaprès2heures55.
(TIME‘9:00:00’,TIME‘9:30:00’)
OVERLAPS
(TIME‘9:29:00’,TIME‘9:31:00’)
L’exempleprécédentrenvoieTrue,carlesdeuxintervallessechevauchentd’uneminute.
(TIME‘9:00:00’,TIME‘10:00:00’)
OVERLAPS
(TIME‘10:15:00’,INTERVAL‘3’HOUR)
L’exemple précédent renvoie False, car les deux intervalles ne serecouvrentpas.
(TIME‘9:00:00’,TIME‘9:30:00’)
OVERLAPS
(TIME‘9:30:00’,TIME‘9:35:00’)
Cet exemple renvoie False, car même si les deux intervalles sontcontigus,ilsnesechevauchentpas.
MATCH
Le respect de l’intégrité référentielle, traitée au Chapitre 5, implique demaintenirlacohérenced’unebasededonnéesquicontientplusieurstables.Vouspouvezperdrecette intégritéenajoutantàune tableenfantune lignesans correspondance dans la table parent. Des problèmes similaires seposent si vous supprimez une ligne de la table parent alors qu’une lignecorrespondanteexistedanslatableenfant.
Supposons à nouveau que vous ayez une tableCLIENTS qui conserve latrace de tous vos clients, et une table VENTES qui enregistre toutes lestransactions.Vousnevoulezévidemmentpasajouterune ligneàVENTEStant que vous n’avez pas saisi dans la table CLIENTS les références duclientquiaeffectuéunachat.Demême,vousnevoulezpassupprimerunclient s’il a effectué un ou plusieurs achats mémorisés dans la tableVENTES. Avant d’effectuer une opération d’insertion ou de suppression,vousdevrezdoncvérifierqu’ellen’engendrepasdesproblèmesd’intégrité.LeprédicatMATCHpeuteffectueruntelcontrôle.
Dansnotreexemple,CLIENT_IDestlacléprimairedelatableCLIENTSetellejouelerôled’unecléétrangèredanslatableVENTES.Chaquelignede la tableCLIENTSdoit comporterunCLIENT_IDunique et non nul.Parcontre,CLIENT_IDn’estpasuniquedans la tableVENTES,carunclient peut effectuer plusieurs achats. Cette situation ne pose pas deproblèmeetnecomprometpasl’intégrité,carCLIENT_IDesticiunecléétrangèreetnonunecléprimaire.
De même, CLIENT_ID peut être nul dans la table VENTES, carquelqu’un peut entrer dans votremagasin, acheter quelque chose et partiravantmêmequevousayezeuletempsdesaisirsonnometsonadressedanslatableCLIENTS.Cettesituationpeutcréerunelignedanslatableenfantqui n’a pas de correspondance dans la table parent. Pour contourner ceproblème,ilsuffitdecréerunclientgénériquedanslatableCLIENTSetdeluiattribuertouslesachatsanonymes.
Supposezqu’uncliententredansvotremagasinetprétendeavoirachetéunF-117AStealthFighterle18mai2006.Ilaperdusonticketdecaisse,maisil veut à tout prix vous rendre l’avion, car il est visible sur les radarsennemis. Vous pouvez vérifier ses propos en recherchant unecorrespondance dans votre base de données. En premier lieu, vous allezrécupérer son CLIENT_ID dans la variable vclientid, puis vousutiliserezlasyntaxesuivante:
...WHERE(:vclientid,‘F-117A’,2006-05-18’)
MATCH
(SELECTCLIENT_ID,PRODUIT_ID,DATE_VENTE
FROMVENTES)
Si une vente de F-117A existe pour ce client à cette date, le prédicatMATCH va renvoyer la valeur True. Vous allez devoir reprendrel’appareildéfectueuxetrembourserleclient.(Note:SiunedesvaleursdupremierargumentdeMATCHestnulle,leprédicatesttoujoursvérifié.)
Les développeurs de SQL ont ajouté les prédicats MATCH et UNIQUEpourlamêmeraison:ilspermettentd’effectuerdestestsexplicitesafindevérifierl’intégritéréférentielleimpliciteetlescontraintesUNIQUE.
LaformegénéraleduprédicatMATCHestlasuivante:
Valeur_ligneMATCH[UNIQUE][SIMPLE]PARTIAL/
FULL]
Sous_requête
Les options UNIQUE, PARTIAL et FULL interviennent quand Va-leur_ligne désigne une ligne dont une ou plusieurs colonnes sontnulles (voir leChapitre9pourplusd’informationssur lesexpressionsdevaleur de ligne). Les règles régissant le prédicatMATCH sont une copiedesrèglesd’intégritéréférentiellecorrespondantes.
Lesrèglesd’intégritéréférentielleetleprédicatMATCHLesrèglesd’intégritéréférentielleimposentquelesvaleursd’unecolonnedansunetablecorrespondentàcellesd’uneouauxcolonnesdelapremièretablecommelacléétrangère,etauxcolonnesde lasecondetablecommeétantlacléprimaireoucléunique.Parexemple,vouspouvezdéclarer lacolonneEMP_NODPTdelatableEMPLOYEcommeunecléétrangèrequiréférence la colonneNODEPTdans la tableDEPT.Cela vous permet devousassurerquesivousenregistrezunemployédans la tableEMPLOYE
comme travaillant au département 123, une ligne dont la valeurNODEPTestégaleà123apparaîtradanslatableDEPT.
Silacléétrangèreetlacléprimaireneconcernentqu’uneseulecolonne,lasituationestassezsimple.Maislesdeuxcléssontsouventforméesàpartirdeplusieurscolonnes.Parexemple,lavaleurNODEPTpeutn’êtreuniqueque pour un seul endroit, si bien que pour identifier parfaitement unecolonneDEPT,vousdevezspécifieràlafoisunLIEUetunNODEPT.Silesbureaux de Boston et de Tampa ont tous deux un département 123, ilscorrespondront à (‘Boston’, ‘123’) et (‘Tampa’, ‘123’). Dans ce cas, latable EMPLOYE doit posséder deux colonnes pour identifier un DEPT.Nommez ces colonnes LIEU_EMP et NODEPT_EMP. Si un employétravaille au département 123 à Boston, LIEU_EMP et NO-DEPT_EMPvaudront respectivement ‘Boston’ et ‘123’. La déclaration étrangère del’employéestalorslasuivante:
FOREIGNKEY(LIEU_EMP,NODEPT_EMP)
REFERENCESDEPT(LIEU,NODEPT)
Tirer des conclusions valides de l’étude de vos données peut devenirextrêmement problématique si elles contiennent des valeurs nulles. Vousallez parfois traiter des données qui contiennent des valeurs nulles d’unecertainefaçon,etdansd’autrescasvousles traiterezd’uneautremanière.Les mots clés UNIQUE, SIMPLE, PARTIAL et FULL sont autant demanièresdetravaillersurdesdonnéesquicontiennentdesvaleursnulles.Sivousn’êtespasconcernéparcettequestion,sautezlerestedecettesectionetpassezdirectementàlasuivante,«Connecteurslogiques».Sinon,lisezattentivementlesparagraphessuivants.Chaqueentréedelalisteprésenteuncasparticulier de valeurs nulles et explique comment le prédicatMATCHlesgère.
VoicilesscénariosquiillustrentlesrèglesrégissantlesvaleursnullesetleprédicatMATCH:
» Lesdeuxvaleurssontdemêmenature:Silesvaleurs
deLIEU_EMPetdeNODEPTsonttoutesdeuxnonnulles
outoutesdeuxnulles,lesrèglesd’intégritéréférentielle
sontlesmêmesquepourdesclésbaséessurunecolonne
uniquedontlesvaleurssontnullesounonnulles.
» Unevaleurestnulleetl’autrepas:Si,parexemple,
LIEU_EMPestnulleetqueNODEPTestnonnulle,ousi
LIEU_EMPestnonnulleetNODEPTestnulle,vousavez
besoindenouvellesrègles.Quellerègleappliquersivous
mettezàjourlatableEMPLOYEaveclesvaleursde
LIEU_EMPetdeNODEPTde(NULL‘123’)ou(‘Boston’,
NULL)?Sixalternativesseprésentent:SIMPLE,PARTIAL
etFULL,chacunecombinéeounonaumotcléUNIQUE.
» LemotcléUNIQUEestprésent:Ilspécifiequ’une
colonnecorrespondantedanslatablerésultatdelasous-
requêtedoitêtreuniquepourqueleprédicatsoitvalidé.
» LesdeuxcomposantsdelavaleurdeRsontnuls:Le
prédicatMATCHestvalidéquelquesoitlecontenudela
tablerésultatdelasous-requêteàcomparer.
» AucundescomposantsdelavaleurdeligneRn’est
nul,SIMPLEestspécifié,UNIQUEn’estpasspécifiéet
aumoinsunelignedelatablesous-requête
correspondàR:leprédicatMATCHrenvoielavaleurTrue.
Sinon,ilretourneFalse.
» AucundescomposantsdelavaleurdeligneRn’est
nul,SIMPLEestspécifié,UNIQUEestspécifiéetau
moinsunelignedelatablerésultatdelasous-requête
estàlafoisUNIQUEetcorrespondàR:leprédicat
MATCHrenvoielavaleurTrue.Sinon,ilretourneFalse.
» Uncomposantdel’expressionvaleurdeligneRestnul
etSIMPLEestspécifié:LeprédicatMATCHestvérifié.
UNERÈGLEDÉMOCRATIQUE
LaversionSQL-89dustandardspécifiaitquelarègleUNIQUEétaitla
règle par défaut sans que quiconque ait débattu de possibles
alternatives. Au cours du développement de la version SQL-92 du
standard, plusieurs propositions furent suggérées. Certaines
personnespréféraientde loin lesrèglesPARTIALetdemandaient à
ce qu’elles soient les uniques règles. Elles estimaient que les règles
UNIQUE de SQL-89 posaient d’énormes problèmes et souhaitaient
qu’elles soient considérées comme un bogue et que les règles
PARTIALsoientjugéescommeétantdescorrections.
D’autres personnes penchaient pour les règles UNIQUE, jugeant les
règlesPARTIALobscures, sujettes à erreurs et inefficaces.D’autres
encore souhaitaient s’en tenir à la discipline supplémentaire offerte
par lesrèglesFULL.Pour finir, les troismotsclés furent intégrésau
standard, si bien que l’utilisateur peut choisir celui qu’il préfère.
SQL:1999 a ajouté à tout cela les règlesSIMPLE. Cette prolifération
rend la gestion des valeurs nulles tout sauf simple. Si SIMPLE,
PARTIALouFULLne sont pas spécifiées, les règlesSIMPLE sont
appliquées.
» Uncomposantquelconquedel’expressionvaleurde
ligneRn’estpasnul,PARTIALestspécifié,UNIQUE
n’estpasspécifié,etlespartiesnonnullesd’aumoins
unelignedelatablerésultatproduiteparlasous-
requêtecorrespondentàR:LeprédicatMATCHrenvoie
lavaleurTrue.Sinon,ilretourneFalse.
» Uncomposantquelconquedel’expressionvaleurde
ligneRn’estpasnul,PARTIALestspécifié,UNIQUEest
spécifié,etlespartiesnonnullesdeRcorrespondent
auxpartiesnonnullesd’aumoinsuneligneuniquede
latablerésultatdelasous-requête:LeprédicatMATCH
renvoielavaleurTrue.Sinon,ilretourneFalse.
» AucundescomposantsdelavaleurdeligneRn’est
nul,FULLestspécifié,UNIQUEn’estpasspécifié,etau
moinsunelignedelatablerésultatdelasous-requête
correspondàR:LeprédicatMATCHrenvoielavaleur
True.Sinon,ilretourneFalse.
» AucundescomposantsdelavaleurdeligneRn’est
nul,FULLestspécifié,UNIQUEestspécifié,etau
moinsunelignedelatablerésultatdelasous-requête
estàlafoisUNIQUEetcorrespondàR:Leprédicat
MATCHrenvoielavaleurTrue.Sinon,ilretourneFalse.
» Uncomposantquelconquedel’expressionvaleurde
ligneRestnul,etFULLestspécifié:LeprédicatMATCH
renvoielavaleurTrue.Sinon,ilretourneFalse.
ConnecteurslogiquesComme lesexemplesprécédents l’ontdémontré,une seuleconditionn’estquelquefoispassuffisantepourrécupérertoutesleslignesquevousvoulezextraire d’une table.Dans certains cas, ces lignes doivent remplir une ouplusieursconditions.Dansd’autressituations,celasuffit simplementà lesqualifier pour la partie suivante. Dans d’autres situations encore, vous
voudrez peut-être récupérer uniquement les lignes qui ne remplissent pascertaines conditions. Pour répondre à tous ces besoins, SQL propose lesconnecteurslogiquesAND,ORetNOT.
ANDSi l’obtentiond’une ligneest soumise à lavalidité conjointedeplusieursconditions,utilisezleconnecteurlogiqueAND.Parexemple:
SELECTNO_FACTURE,DATE_VENTE,VENDEUR,
TOTAL_VENTE
FROMVENTES
WHEREDATE_VENTE>=‘2006-05-15’
ANDDATE_VENTE<=‘2006-05-21’;
LaclauseWHEREdoitremplirlesdeuxconditionssuivantes:
» DATE_VENTEdoitêtresupérieurouégalau15mai2006.
» DATE_VENTEdoitêtreinférieurouégalau21mai2006.
Seulesleslignesquicorrespondentàdesventeseffectuéesdanslasemainedu15mai2006remplissentlesdeuxconditions.Larequêteneretournequeceslignes.
RemarquezqueleconnecteurANDeststrictementlogique.Cetterestrictionpeut prêter quelquefois à confusion, car certaines personnes emploient lemot«et»(AND)dansuncontextemoinsprécis.Parexemple,votrepatronvous dit : « Je voudrais voir les résultats des ventes de Dupont etNemours. » Il a dit Dupont et Nemours ; par conséquent, vous allezcertainementécrirelarequêteSQLsuivante:
SELECT*
FROMVENTES
WHEREVENDEUR=‘Dupont’
ANDVENDEUR=‘Nemours’;
Maisenfaitvotrepatronavaituneautreidéeentête:
SELECT*
FROMVENTES
WHEREVENDEURIN(‘Dupont’,‘Nemours’);
Lapremière requêtene retournera rien, car aucunedesventesde la tableVENTES n’a été effectuée à la fois par Dupont et Nemours. La seconderequête renverra les informations concernant les ventes effectuées parDupont ou par Nemours, et c’est ce que votre patron demandaitprobablement.
ORSiuneouplusieursconditionsdoiventêtrevalidéespourqu’unelignesoitretournéecommerésultat,utilisezleconnecteurlogiqueOR.Parexemple:
SELECTNO_FACTURE,DATE_VENTE,VENDEUR,
TOTAL_VENTE
FROMVENDEUR
WHEREVENDEUR=‘Dupont’
ORTOTAL_VENTE>2000;
Cette requête retourne toutes les ventes faites parDupont, quelle que soitleur importance,ainsique toutes lesventesdeplusde2000eurosquellequesoitlapersonnequilesaeffectuées.
NOTLe connecteur de négationNOT inverse le sens d’une condition. Si uneconditiondoitnormalementretournerunevaleurvraie,ajouterNOTluifaitrenvoyer une valeur fausse. Si une condition renvoie normalement unevaleur fausse, ajouter NOT lui fait retourner une valeur vraie. Prenonsl’exemplesuivant:
SELECTNO_FACTURE,DATE_VENTE,VENDEUR
FROMVENTES
WHERENOT(VENDEUR=‘Dupont’);
CetterequêteretourneleslignesdetouteslesventesquelesvendeursautresqueDupontonteffectuées.
Lorsque vous utilisezAND,OR etNOT, il peut arriver que la portée duconnecteur ne soit pas claire. Utilisez des parenthèses pour vous assurerque SQL l’applique au prédicat voulu. Dans l’exemple précédent, leconnecteurNOTs’appliqueauprédicat(VENDEUR=‘Dupont’).
ClausesGROUPBYSivousrécupérezdeslignesd’unetableenutilisantl’instructionSELECT,ceslignesvoussontretournéespardéfautdansl’ordreoùellesapparaissentdans la table source. Cet ordre n’a quelquefois aucun sens. La clauseGROUPBYvouspermetalorsdespécifieruneouplusieurscolonnesquidéterminentl’appartenanced’uneentréeàungroupe.Précisonscela.
Supposezquevoussoyezunresponsablecommercialetquevoussouhaitiezexaminer les performances de votre force de vente pour une semainedonnée.Lesinformationsproduitesdoiventêtregroupéesparvendeur.Vouspourriezsimplementécrirel’instructionsuivante:
SELECTNO_FACTURE,DATE_VENTE,VENDEUR,
TOTAL_VENTE
FROMVENTES;
LaréponseseprésenteraitalorscommeàlaFigure10.1.
FIGURE10.1Résultatdesventesd’unepériodedonnée.
Commeiln’yaquepeudeventes,cerésultatvousdonnedéjàunecertaineidée du travail de vos représentants. Evidemment, dans la vraie vie, il yauraitbeaucoupplusdeventes(heureusement!),etilseraitdifficiledediresi vos objectifs ont été atteints. Pour obtenir l’analyse dont vous avezbesoin,vouspouvezcombineruneclauseGROUPBYavecdes fonctionsd’agrégation (ou d’ensemble) afin d’afficher une vision quantitative desperformancesdudépartementcommercial.L’instructionsuivanteclasselesvendeursselonlamoyennedeleurchiffred’affaires:
SELECTVENDEUR,AVG(VENTE_TOTAL)
FROMVENTES
GROUPBYVENDEUR;
Le résultat de cette requête, exécutée dans Microsoft Access 2013, estillustréàlaFigure10.2.Vouspouvezl’exécuteravecunautregestionnairedebasededonnées,maislerésultataffichéserapeut-êtredifférent:
À l’évidence, la moyenne des ventes de Dupont est considérablementsupérieureàcelledesescollègues.Vouspouvezvérifierlavéracitédecefaitendemandantletotaldesventesréaliséesparchaquecommercial:
SELECTVENDEUR,SUM(VENTE_TOTAL)
FROMVENTES
GROUPBYVENDEUR;
CequiafficheralerésultatreproduitàlaFigure10.3quiestcohérentaveclesinformationsprécédentes.
FIGURE10.2Lamoyennedesventesdechaquevendeur.
FIGURE10.3Totaldesventesdechaquevendeur.
LesclausesHAVINGUneclauseHAVINGestunfiltrequiappliqueunerestrictionsur la tablevirtuellequ’uneclauseGROUPBYvientdecréer.ToutcommeuneclauseWHERE exclut des lignes d’une requête, une clause HAVING exclut desgroupes.
Reprenonsl’exempledelasectionprécédente.SupposezqueleresponsablecommercialveuilleseconcentrersurlesperformancesdesvendeursautresquecellesdeDupont(vusesrésultats,ildoitconstitueruneclasseàluitout
seul).Vous pouvez le lui permettre en ajoutant une clauseHAVING à larequêteprécédente,commesuit:
SELECTVENDEUR,SUM(VENTE_TOTAL)
FROMVENTES
GROUPBYVENDEUR;
HAVINGVENDEUR<>‘Dupont’;
Lerésultatseralesuivant:
VENDEURTotal
------------------
Nemours12.48
Podoleck12.00
LesclausesORDERBYUtilisezlaclauseORDERBYpourafficherunetablerésultatdansunordrealphabétique croissant ou décroissant. Alors que la clause GROUP BYréunit les lignes par groupes classés par ordre alphabétique, la clauseORDERBY trie pour sa part des lignes individuelles. Elle doit être ladernière clause que vous spécifiez dans une requête. Si cette requêtecontient également la clause GROUP BY, celle-ci provoque d’abord unregroupement des lignes, puis la clause ORDER BY trie ces lignes àl’intérieurdechacundesgroupesquiaurontété formés.Sivousn’utilisezpas la clause GROUP BY, l’instruction considère la table tout entièrecommeungroupe.ORDERBYtriealorstoutesceslignesenfonctiondelacolonneoudescolonnesquevousaurezspécifiées.
Pour illustrer cela, considérez les données de la table VENTES. EllecontientdescolonnespourNO_FACTURE,DATE_VENTE,VENDEUR etTOTAL_VENTE. Si vous utilisez l’exemple suivant, vous pourrezvisualiserlesdonnéesVENTESselonunordrearbitraire:
SELECT*FROMVENTES;
Dansunecertaineimplémentation,l’ordredutripeutêtreceluidanslequelvousavezinsérédeslignesdanslatable.Dansd’autrescas,leclassementsera celui de la dernière mise à jour. Et si quelqu’un a physiquementréorganisé labasededonnées, le résultat serapratiquement imprévisible.En règle générale, vous devez spécifier l’ordre dans lequel vous voulezvisualiserlesdonnées.Vouspouvezparexempletrierleslignesenfonctiondeladatedevente(DATE_VENTE)delamanièresuivante:
SELECT*FROMVENTESORDERBYDATE_VENTE;
Cet exemple retourne toutes les lignes de la table VENTES groupées enfonctiondeDATE_VENTE.
Les lignesdont les colonnesDATE_VENTEsont identiques seront triéesentre elles selon un ordre par défaut qui dépend de l’implémentation.Cependant, vous pouvez spécifier vous-même comment trier les lignes enfonction de la date de vente, par exemple dans l’ordre des numéros defactures:
SELECT*FROMVENTESORDERBYDATE_VENTE,
NO_FACTURE;
Cette requête trie tout d’abord les ventes parDATE_VENTE. Puis, pourchaque date de vente, elle ordonne les résultats par NO_ FACTURE.Attention!Neconfondezpascetexempleaveclarequêtesuivante:
SELECT*FROMVENTESORDERBYNO_FACTURE,
DATE_VENTE;
Cette requête trie d’abord les ventes par NO_FACTURE, puis parDATE_VENTEpourchaqueNO_FACTUREdifférent.Cequineproduiraprobablementpaslerésultatescompté,carilestpeuvraisemblablequ’uneseulefacturecomporteplusieursdates.
La requête suivante est un autre exemple de la manière dont SQL peutretournerlesdonnées:
SELECT*FROMVENTESORDERBYVENDEUR,DATE_VENTE
;
Cetexempletrieparvendeur,puispardatedevente.Unefoislesdonnéesvisualiséesdanscetordre,vouspouvezl’inverserdelamanièresuivante:
SELECT*FROMVENTESORDERBYDATE_VENTE,VENDEUR
;
Cet exemple trie les lignes selon DATE_VENTE, puis selon la colonneVENDEUR.
Tous ces exemples de tri se font par défaut en ordre croissant (ASC). LedernierSELECTclassetoutd’abordlesVENTESencommençantparlesplus récentes, puis, pour une date donnée, affiche les VENTES pour‘Albert’ avant ‘Bernard’. Si vous préférez un ordre décroissant (DESC),vouspouvezlespécifierpouruneouplusieurscolonnesdetridelamanièresuivante:
SELECT*FROMVENTES
ORDERBYDATE_VENTEDESC,VENDEURASC;
Cetexemplespécifieunordredécroissantpourlesdatesdevente(lesplusrécentesétantdoncaffichéesenpremier),puisunordrecroissantpourlesvendeurs,cequilesclasseparordrealphabétique.
LeslimitesdeFetchQuandonachangélestandardISO/IECSQL,onadéveloppésescapacitésde langage, cequi est en soiunebonnechose.Mais il arrivequelquefoisque de tels changements ne permettent pas d’anticiper toutes lesconséquencespossibles.C’estcequi s’estproduitavec les limitationsdeFETCHdansSQL:2008.
L’idéedelimiterFETCHestdueaufaitqu’uneinstructionSELECTpeutretournerunnombreindéterminédelignes,alorsquequelquefoisseuleslestroisoulesdixpremièreslignessontintéressantes.C’estdanscetespritquel’onaajoutédansSQL::2008lasyntaxesuivante:
SELECTVendeur,AVG(TOTAL_VENTE)
FROMVENTES
GROUPBYVendeur
ORDERBYAVG(TOTAL_VENTE)DESC
FETCHFIRST3ROWSONLY;
Toutvabien.Vousobtenezainsi lesnomsdestroispremiersvendeursquiontvendudesproduitstrèschers.Maisilresteunpetitproblème:quefairesi ces troisvendeursont lemême totaldeventes ?Seul l’undeces troisnomsseraretourné.Lequel?C’estindéterminé.
L’indétermination n’est pas acceptable pour toute personne qui est chargéd’unebasededonnéesdignedesonnom,c’estlaraisonpourlaquelleonacorrigélasyntaxedansSQL:2011.Onainclusdesliensdecettemanière:
SELECTVendeur,AVG(TOTAL_VENTE)
FROMVENTES
GROUPBYVendeur
ORDERBYAVG(TOTAL_VENTE)DESC
FETCHFIRST3ROWSWITHTIES;
Àprésent, le résultat est complètement déterminé : s’il y a un lien, vousobtiendrez toutes les lignes liées. Comme avant, si vous vous arrêtez aumodificateurWITHTIES,lerésultatseraindéterminé.
MaisSQL:2011apporteaussideuxautresaméliorationsàFETCHlimité.
La première est que les pourcentages sont traités comme un nombrespécifiquedelignes.Considérezcetexemple:
SELECTVendeur,AVG(TOTAL_VENTE)
FROMVENTES
GROUPBYVendeur
ORDERBYAVG(TOTAL_VENTE)DESC
FETCHFIRST10PERCENTROWSONLY;
Unproblèmede lienspeutapparaître lorsque l’on traitedespourcentagescomme de simples numéros d’enregistrements, c’est pourquoi la syntaxeWITHTIESest ici utilisée.Vous pouvez ou non inclure des liens, toutdépenddecequevoussouhaitezfairedansunesituationdonnée.
Deuxièmement, supposez que vous ne souhaitiez pas obtenir les troispremiersoulesdixpremierspourcentages,maislesecondouletroisièmepourcentage.Peut-êtrevoulez-vouspasserdirectementàunpointquivoussembleplusintéressant.SQL:2011vouspermetaussidetraitercetypedecas.Considérezlecodeci-dessous:
SELECTVendeur,AVG(TOTAL_VENTE)
FROMVENTES
GROUPBYVendeur
ORDERBYAVG(TOTAL_VENTE)DESC
OFFSET3ROWS
FETCHNEXT3ROWSONLY;
Le mot clé OFFSET indique le nombre de lignes à sauter avant derécupérer.LemotcléNEXTspécifiequeleslignesàrécupérersontcellesquisesituentimmédiatementaprèsl’offset.Puislenomduvendeurquialaquatrième, cinquième ou sixième moyenne la plus élevée de ventes estretourné.Commevouspouvezleconstater,sanslasyntaxeWITHTIES,ilyauraitencoreunproblèmed’indétermination.Siletroisièmeouquatrièmeou cinquième vendeur sont liés, est indéterminé lequel est traité dans lepremierlot,lequeldanslesecondlot.
Ilvautmieuxéviterd’utiliserlacapacitédelimitationdeFETCH,carellerisquederetournerdesrésultatsquiinduisentenerreur.
Regarderparunefenêtrepourcréerunjeuderésultats
Les fenêtres et les fonctions de fenêtre ont été d’abord introduites dansSQL:1999.Grâceàunefenêtre, l’utilisateurpeutpartitionnerunensemblededonnées,éventuellementclasserleslignesparpartitionsetspécifierunesuitedelignes(lecadredelafenêtre)quiestassociéeàunelignedonnée.
Lecadrede la fenêtrede la ligneRestun sous-ensemblede lapartitioncontenantR.Parexemple,lecadredelafenêtrepeutsecomposerdetoutes
les lignesdudébut à la finde lapartitionycomprisR, en fonctionde lamanièredontsontclasséesleslignesdanslapartition.
Une fonction de fenêtre calcule une valeur de la ligneRen fonction deslignesdanslecadredeR.
Par exemple, supposons que vous ayez une tableVENTESqui comportedes colonnes CLIENT_ID, NO_FACTURE et TOTAL_VENTE. Leresponsabledumagasinveutconnaîtrelemontanttotaldesachatsqu’afaitchaqueclientsurunnombrespécifiquedefactures.Vouspouvezobtenircesinformationsàl’aideducodesuivant:
SELECTCLIENT_ID,NO_FACTURE,
SUM(TOTAL_VENTE)OVER
(PARTITIONBYCLIENT_ID
ORDERBYNO_FACTURE
ROWSBETWEEN
UNBOUNDEDPRECEDING
ANDCURRENTROW)
FROMVENTES;
La clause OVER détermine le nombre de lignes de la requête qui sontpartitionnéesavantletraitement.Icic’estlafonctionSUM.Unepartitionestallouéeàchaqueclient.Chaquepartitionaunelistedenumérosdefacture,chacuneassociéeàlasommedesvaleursdeTOTAL_VENTEd’unerangéespécifiquedeligne,pourchaqueclient.
DansSQL:2011lafonctionnalitéoriginaledefenêtreaconnud’importantesaméliorations,notammentavecl’apparitiondenouveauxmotsclés.
PartitionnerunefenêtreenpaquetsavecNTILELafonctiondefenêtreNTILEdistribueleslignesd’unepartitiontriéedansunnombreentierpositifdegroupes.Lesgroupessontnumérotésàpartirdeunàn.Silenombredelignesdansunepartitionmn’estpasdivisibleparn,alors une fois que la fonction NTILE a distribué un nombre à chaque
groupe,lerestem/n,appelér,estréattribuéaupremiergrouper,lerendantainsiungroupeplusgrandquelesautres.
Supposez que vous souhaitiez classer vos employés par salaire, en lesclassantdanscinqgroupesdesalaireduplushautauplusbas.Vousleferezaveclecodesuivant:
SELECTPRENOM,NOM,NTILE(5)
OVER(ORDERBYSALAIREDESC)
ASBUCKET
FROMEMPLOYE;
Si vous avez 11 employés, chaque groupe comptera deux employés, àl’exception du premier, qui en comportera trois. Le premier groupe seraceluides troisemployés lesmieuxpayés,et lecinquièmegroupeaura lesdeuxemployéslesmoinsbienpayés.
NaviguerdansunefenêtreSQL:2011comportecinq fonctionsde fenêtrequiévaluentuneexpressiondansuneligneR2quisetrouvequelquepartdanslecadredelafenêtredela ligne actuelle R1. Ces fonctions sont LAG, LEAD, NTH_VALUE,FIRST_VALUEetLAST_VALUE.
Cesfonctionsvouspermettentderetrouverdesinformationsdansdeslignesspécifiéesquisontàl’intérieurducadredelafenêtredelaligneactuelle.
FonctionLAGLa fonctionLAGvous permet de récupérer des informations de la ligneactuellede la fenêtrequevousexaminezainsiquedes informationsd’uneautrelignequevousavezspécifiéeetquiprécèdelalignecourante.
Supposezquevousdisposiezd’unetablequienregistrelesventestotalesdechaque jour de l’année en cours.Vous pourrez ainsi connaître lemontanttotaldesventesparjouretcomparerlemontantdesventesd’aujourd’huiàceluid’hierparexemple.VousleferezenutilisantlafonctionLAGcommesuit:
SELECTTOTAL_VENTEASVENTE_DU_JOUR,
LAG(TOTAL_VETE)OVER
(ORDERBYDATE_VENTE)ASPrevDaySale
FROMTOTAL_JOUR;
PourchaquelignedeTOTAL_JOUR,larequêteretourneraunelignelistantlalignedutotaldujouretcellequicalculeletotaldelaveille.L’offsetpardéfaut est à 1, c’est la raison pour laquelle le résultat de la veille estretournéetnonceluid’unautrejour.
Pourcomparer lesventesdu jouràcellesd’unesemaineavant,utilisez lecodesuivant:
SELECTTOTAL_VENTEASVENTE_DU_JOUR,
LAG(TOTAL_VENTE,7)OVER
(ORDERBYDATE_VENTE)ASPrevDaySale
FROMTOTAL_JOUR;
Les sept premières lignes dans le cadre de la fenêtre n’auront pas deprécédentantérieuràunesemaine.LaréponsepardéfautdanscecasestderetournerunrésultatnullpourPrevDaySale.Sivoussouhaitez faireapparaître un résultat autre que null, spécifiez que vous voulez voirretournerlavaleur0,parexemple,etnonlavaleurnullcommesuit:
SELECTTOTAL_VENTEASVENTE_DU_JOUR,
LAG(TOTAL_VENTE,7,0)OVER
(ORDERBYDATE_VENTE)ASPrevDaySale
FROMTOTAL_JOUR;
Pardéfaut, icinesontcomptabiliséesqueles lignesquisont trèsgrandes,commec’estlecasdeTOTAL_VENTE,quipeutcontenirunevaleurnulle.Sivousvoulezsautertoutesleslignesquiontunevaleurnulleetneprendreencomptequecellesquiontunevaleurréelle,ajoutezlemotcléIGNORENULLScommedanscettevariantedel’exempleprécédent:
SELECTTOTAL_VENTEASVENTE_DU_JOUR,
LAG(TOTAL_VENTE,7,0)IGNORENULLS
OVER(ORDERBYDATE_VENTE)ASPrevDaySale
FROMTOTAL_JOUR;
FonctionLEADLafonctionLEADfonctionneexactementcommelafonctionLAG,exceptéqu’elle n’examine pas la ligne précédente, mais la suivante. En voici unexemple;
SELECTTOTAL_VENTEASVENTE_DU_JOUR,
LEAD(TOTAL_VENTE,7,0)IGNORENULLS
OVER(ORDERBYDATE_VENTE)ASNextDaySale
FROMTOTAL_JOUR;
FonctionNTH_VALUELa fonctionNTH_VALUE est semblable aux fonctionsLAG etLEAD, àl’exception près qu’elle n’évalue pas une expression dans une ligneprécédente ou suivante de la ligne en cours, mais qu’elle évalue uneexpression dans une ligne qui est à un offset spécifié de la première oudernièrelignedanslecadredelafenêtre.
Envoiciunexemple:
SELECTTOTAL_VENTEASCHOIX_VENTE,
NTH_VALUE(TOTAL_VENTE,2)
FROMFIRST
IGNORENULLS
OVER(ORDERBYDATE_VENTE)
ROWSBETWEEN10PRECEDINGAND10FOLLOWING)
ASPREMIERE_VENTE
FROMTOTAL_JOUR;
Danscetexemple,PREMIERE_VENTEestévaluéeainsi:
» Lecadredelafenêtreassociéàlaligneencoursest
formé.Cequiinclutlesdixlignesprécédentesetsuivantes.
» TOTAL_VENTEestévaluédanschaqueligneducadrede
lafenêtre.
» IGNORENULLSestspécifié,toutesleslignescontenant
unevaleurnullepourTOTAL_VENTEsontsautées.
» Oncommenceaprèslapremièrevaleurquiresteunefois
lesvaleursnullespourTOTAL_VENTEexclues,onavance
dedeuxlignesàlafoisparcequeFROMFIRSTétait
spécifié.
LavaleurPREMIERE_VENTEestlavaleurdeTOTAL_VENTEdansunelignespécifiée.
Si vous ne voulez pas sauter les lignes qui ont une valeur nulle pourTOTAL_VENTE, spécifiez RESPECT NULLS à la place de IGNORENULLS. La fonction NTH_VALUE fonctionne de la même manière, quevousprécisiezFROMLAST ouFROMFIRST, sauf si vous comptez àrebours à partir du dernier enregistrement et non à partir du premierenregistrement.Lenombredelignesàcompteresttoujourspositif,quevouscomptiezàreboursouenavant.
FonctionsFIRST_VALUEetLAST_VALUELesfonctionsFIRST_VALUEetLAST_VALUEsontdescasspéciauxdela fonction NTH_VALUE ; FIRST_VALUE est l’équivalent deNTH_VALUE où FROM FIRST est spécifié et l’offset vaut 0 (zéro).LAST_VALUE est l’équivalent deNTH_VALUEoùLAST_VALUE estspécifiéet l’offsetvaut0.Pour lesdeux fonctions,vousavez le choixderespecteroud’ignorerlesvaleursnulles.
ImbriquerdesfonctionsdefenêtreImbriquerunefonctiondansuneautrepeutêtrequelquefoislasolutiondontvousavezbesoin.DansSQL:2011,cettepossibilitéaétéajoutéeetétendue
auxfonctionsdefenêtre.
Un investisseur cherche àdéterminer si c’est le bonmomentd’acheter unstockparticulier.Afindebienarrêtersonchoix, ildécidedecomparer leprixdustockactuelauxprixdes100derniersfournisseursquil’ontvendu.Ilsedemandedecombienestmoinscher leprixdes100fournisseursquil’ontvenduparrapportauprixactuel.Pouravoiruneréponsesatisfaisante,ileffectuelarequêtesuivante:
SELECTDATE_VENTE,
SUM(CASEWHENPRIX_VENTE<
VALUEOF(PRIX_VENTEATCURRENTROW)
THEN1ELSE0)
OVER(ORDERBYDATE_VENTE
ROWSBETWEEN100PRECEDINGANDCURRENTROW)
FROMSTOCK_VENTE;
La fenêtre inclut les 100 lignes précédant la ligne en cours, lesquellescorrespondentaux100ventesimmédiatementantérieuresaumomentactuel.Àchaquefoisqu’uneligneoùlavaleurdePRIX_VENTEestinférieureauprixdeventeactuel,onajoute1àlasomme.Lerésultatfinalestunnombrequiindiquelenombredeventesparmiles100précédentesquiontunprixinférieurauprixactuel.
ÉvaluerungroupedelignesIlpeutarriverque lesclésde triquevousavezchoisiespourclasserunepartitionpeuventavoirdesdoubles.Pourévaluertoutesleslignesquiontlamême clé de tri sous forme de groupe, utilisez l’option GROUPS. Vouspourrezainsicompterlesgroupesdelignesquiontuneclédetriidentique.
Envoiciunexemple:
SELECTCLIENT_ID,DATE_VENTE,
SUM(TOTAL_FACTURE)OVER
(PARTITIONBYCLIENT_ID
ORDERBYDATE_VENTE
GROUPSBETWEEN2PRECEDINGAND2FOLLOWING)
FROMCLIENTS;
Lecadredefenêtredecetexemplesecomposedecinqgroupesdelignes:deux groupes avant le groupe contenant la ligne actuelle, le groupe de laligneactuelle,etdeuxgroupesquisuiventlegroupedelaligneactuelle.LeslignesdechaquegroupeontlamêmeDATE_VENTEet laDATE_VENTEassociéeàchaquegroupeestdifférentedesvaleursdeDATE_VENTEdesautresgroupes.
S
Chapitre11Lesopérateursrelationnels
DANSCECHAPITRE:
» Combinerdestablesdemêmestructure.
» Combinerdestablesdestructuresdifférentes.
» Récupérerdesdonnéespertinentesdepuisplusieurstables.
QLestunlangagederequêtespourlesbasesdedonnéesrelationnelles.Dans les précédents chapitres, j’ai présenté des bases de donnéesélémentaires et, dans la plupart des cas, mes exemples ne faisaient
référencequ’àuneseuletable.Ilesttempsdemettreunpeuderelationneldanslabasededonnées!Aprèstout,unebaseestqualifiéederelationnellequandellecontientplusieurstablesliéesentreelles.
Commeunebasededonnées relationnellecontientunensemblede tables,une requête extrait généralement des informations à partir de plusieurstables.SQLdisposed’opérateursquipermettentdecombinerdesdonnéesissuesdeplusieurs sources au seind’une seule table résultat.Ce sont lesopérateurs UNION, INTERSECT et EXCEPT ainsi que la famille desopérateursJOIN. Chacun d’entre eux combine des données provenant deplusieurstablesd’unemanièredifférente.
UNIONL’opérateur UNION est l’implémentation SQL de l’opérateur union del’algèbrerelationnelle. Ilvouspermetd’extrairedes informationsdedeuxouplusieurstablesdemêmestructure.Demêmestructuresignifieque:
» Lestablesdoiventtoutesavoirlemêmenombrede
colonnes.
» Lescolonnescorrespondantesdoiventposséderdes
donnéesdemêmetypeetdemêmelongueur.
Lorsque ces conditions sont satisfaites, les tables sont déclaréescompatibles pour une union. L’union de deux tables retourne toutes leslignesdechaquetableetéliminelesdoublons.
Supposonsquevouscréiezunebasededonnéespourgérerdesstatistiquessur le base-ball (comme celle duChapitre 12). Elle contient deux tablesnommées AMERICAINE et NATIONALE qui sont compatibles pour uneunion.Toutesdeuxont troiscolonnes,et lescolonnescorrespondantesonttoujours lemême type.Deplus, les colonnes correspondantesportentdesnoms identiques (même si cette condition n’est pas requise pour que cestablessoientdéclaréescompatiblespouruneunion).
NATIONALEcontientlesnomsdeslanceursdelaLiguenationaleainsiquelenombredepartiescomplètesauxquellesilsontparticipé.AMERICAINEcontient les mêmes informations, mais sur les lanceurs de la Ligueaméricaine. L’union des deux tables est une table qui contient toutes leslignesdelapremièretableettoutesleslignesdelaseconde.
SELECT*FROMNATIONALE;
PRENOMNOMPARTIES_COMPLETES
-------------------------------------
SalMaglie11
DonNewcombe9
SandyKoufax13
DonDrysdale12
SELECT*FROMAMERICAINE;
PRENOMNOMPARTIES_COMPLETES
-------------------------------------
WhiteyFord12
DonLarson10
BobTurley8
AllieReynolds14
SELECT*FROMNATIONALE
UNION
SELECT*FROMAMERICAINE;
PRENOMNOMPARTIES_COMPLETES
-------------------------------------
AllieReynolds14
BobTurley8
DonDrysdale12
DonLarson10
DonNewcombe9
SalMaglie11
SandyKoufax13
WhiteyFord12
La variante UNION DISTINCT fonctionne exactement de la mêmemanière.AvecousanslaprécisionDISTINCT,l’opérateurUNIONéliminepardéfauttoutesleslignesendoubledujeuderésultat.
J’ai utilisé un astérisque (*) pour adresser plus rapidement toutes lescolonnesd’une table.CettenotationpeutvousposerdesproblèmesquandvousutilisezdesopérateursrelationnelsdansduSQLincorporéoudansdesmodules.Queva-t-ilsepassersivousajoutezuneouplusieurscolonnesàune table etpasà l’autre,ou sivousajoutezdescolonnesdifférentesauxdeuxtables?Simplement,ellesneserontpluscompatiblespouruneunion.Votre programme sera donc invalide lors de sa prochaine compilation.Même si deux colonnes identiques sont ajoutées aux deux tables de sortequ’elles restent compatibles pour une union, votre programme ne seravraisemblablement pas informé de l’existence de ces nouvelles données.Par conséquent, il vaut toujours mieux dresser la liste explicite descolonnesquevouscomptezutiliserplutôtquedesereposersurleraccourci*.Mais lorsquevousvouscontentezdesaisirdes requêtesSQLdepuis laconsole, l’utilisation de l’astérisque ne pose probablement pas deproblème.Silarequêteéchoue,vouspouvezeneffetafficherrapidementla
structurede la table résultat afindevérifier s’il y a ounon compatibilitépourl’union.
L’opérationUNIONALLCommejel’aiindiquéplushaut,l’opérationUNIONéliminenormalementlesdoublons,cequiestlaplupartdutempslabonneméthode.Cependant,ilpeut arriver que vous désiriez conserver ces lignes redondantes. VousutiliserezalorsUNIONALL.
Pourreprendrel’exempleprécédent,supposonsqueBobTurleysoitpasséencoursdesaisondel’équipeNewYorkYankeesdelaLigueaméricaineàl’équipeBrooklynDodgersde laLiguenationale.Supposonsensuitequ’ilait joué huit parties complètes pour chaque équipe lors de cette saison.L’utilisationd’UNIONéliminera systématiquement l’une des deux lignesconcernant Turley. Même s’il semble qu’il n’ait joué que huit partiescomplèteslorsdecettesaison,ilaenréalitéfait16matchesenentier.Larequêtesuivanteproduiralebonrésultat:
SELECT*FROMNATIONALE
UNIONALL
SELECT*FROMAMERICAINE
Vouspouvezparfois former l’uniondedeux tables,mêmesi ellesne sontnormalementpascompatiblespourcela.Si lescolonnesquevousdésirezavoirdanslatablerésultatsontprésentes,etsiellessontcompatiblesdanslesdeux tables,vousavez lapossibilitéd’effectueruneopérationUNIONCORRESPONDING. Seules les colonnes que vous spécifiez alors sontutiliséespour réaliser l’union,etcesontaussi lesseulesquiapparaissentdanslatablerésultat.
L’opérationLesstatisticiensdubase-ballconserventdesstatistiquestrèsdifférentessurleslanceursetsurlesautresjoueurs.Maisdanslesdeuxcas,ilsconserventle nom et le prénom de chaque sportif. Bien que ces tables soientincompatibles,vouspouvezprocéderàleurunionpournerécupérerqueles
noms, lesprénoms,et,disons, leserreurscommisespar lesunsetpar lesautres:
SELECT*
FROMJOUEURS
UNIONCORRESPONDING
(PRENOM,NOM,ERREURS)
SELECT*
FROMLANCEURS;
La table résultante va afficher les noms, prénoms et nombre d’erreurscommises par tous les joueurs, lanceurs ou non.Comme pour une simpleUNION, tous les doublons sont éliminés. Dans l’hypothèse où un joueurauraitchangédeposteencoursdesaison,unepartiedesstatistiquesquileconcernentseraientdoncperdues.Pouréviterceproblème,vousdisposezdelavarianteUNIONALLCORRESPONDING.
Chaque nom de colonne cité dans la liste qui suit le mot cléCORRESPONDINGdoitexisterdanslesdeuxtables.Sivousomettezcetteliste, toutes les colonnes qui apparaissent dans les deux tables serontutilisées. Mais cette liste implicite peut changer si des colonnes sontajoutéesultérieurement à l’uneou auxdeux tables.C’est pourquoi il vauttoujoursmieuxdresserunelisteexplicitedesnomsdescolonnesquevoussouhaitezutiliser.
INTERSECTL’opérateurUNIONproduitunetablerésultatquicontienttoutesleslignesqui apparaissent dans n’importe laquelle des tables sources. Si vous nevoulezfaireapparaîtrequeleslignesquiapparaissentdanstouteslestablessources, vous pouvez utiliser l’opérateur INTERSECT, qui estl’implémentationSQLdel’opérateurintersectiondel’algèbrerelationnelle.Reprenonsl’exempleprécédent:
SELECT*FROMNATIONALE;
PRENOMNOMPARTIES_COMPLETES
------------------------------------
SalMaglie11
DonNewcombe9
SandyKoufax13
DonDrysdale12
BobTurley8
SELECT*FROMAMERICAINE;
PRENOMNOMPARTIES_COMPLETES
------------------------------------
WhiteyFord12
DonLarson10
BobTurley8
AllieReynolds14
Avec l’instruction qui suit, seules les lignes apparaissant dans toutes lestablessourcesfigurentdanslatablerésultat:
SELECT*
FROMNATIONALE
INTERSECT
SELECT*
FROMAMERICAINE;
PRENOMNOMPARTIES_COMPLETES
------------------------------------
BobTurley8
La table résultat nous indique queBobTurley est le seul lanceur à avoirparticipéaumêmenombredepartiescomplètesdanslesdeuxligues.Note:commeavecUNION,INTERSECTDISTINCTretournelemêmerésultatquel’opérateurINTERSECTutiliséseul.Danscetexemple,seulelalignementionnantBobTurleyestretournée.
LesmotsclésALLetCORRESPONDING fonctionnentavecunopérateurINTERSECTdelamêmemanièrequ’avecUNION.SivousutilisezALL,
les lignes redondantes apparaissentdans la table résultat.Si vousutilisezCORRESPONDING, les tables dont vous calculez l’intersection n’ont pasbesoin d’être compatibles pour l’union, même si les colonnescorrespondantesdoiventêtredumêmetypeetdelamêmelongueur.
VoicicequevousobtiendrezavecINTERSECTALL:
SELECT*
FROMNATIONAL
INTERSECTALL
SELECT*
FROMAMERICAINE;
PRENOMNOMPARTIES_COMPLETESs
------------------------------
BobTurley8
BobTurley8
Prenons un autre exemple. Une municipalité gère la liste des téléphonesportablesquiéquipent sesélus, sesofficiersdepolice, sespompiers, seschefs de service et autres employés municipaux. Une table appeléeTELVILLEcontientdesinformationssurtouslesappareilsenservice.UneautretablenomméeHS,dontlastructureestidentique,contientlesdonnéessur tous les portables qui, pour une raison ou une autre, ont été déclarésinutilisables. Aucun téléphone ne devrait figurer simultanément dans lesdeuxtables.VouspouvezutiliserunopérateurINTERSECTpourvérifierquecetterègleestbienappliquée:
SELECT*
FROMTELVILLE
INTERSECTCORRESPONDING(TELEPHONE_ID)
SELECT*
FROMHS;
Si la table résultat contient des lignes, vous savez que vous avez unproblème.Carcelasignifiequ’untéléphoneestàlafoisenserviceethorsservice, ce qui est incohérent. Une fois le défaut localisé, vous pouvez
corrigerlasituationenexécutantuneopérationDELETEsurunedestablesafinderestaurerl’intégritédelabase.
EXCEPTL’opérateurUNIONtraitedeuxtablessourcesetretournetoutesleslignesqui apparaissentdans lesdeux tables.L’opérateurINTERSECT retournetoutes les lignes qui apparaissent à la fois dans les deux tables. Parcontraste,l’opérateurEXCEPT(ouEXCEPTDISTINCT)retournetoutesles lignes qui apparaissent dans la première table, mais pas dans laseconde.
Reprenons l’exemple des téléphones portables de la base de donnéesmunicipale. Certains appareils avaient été déclarés hors service etretournés chez le fabricant pour réparation. Ils sont maintenant rentrés etremisenservice.LatableTELVILLEaétémiseàjourpouryréintégrerlestéléphonesréparés.Mais,pouruneraisonquelconque,cesappareilsn’ontpas été supprimés de la table HS, alors qu’ils auraient dû l’être. Vouspouvez afficher les numéros TELEPHONE_ID de la table HS tout enéliminant les références des téléphones remis en service à l’aide del’opérateurEXCEPT:
SELECT*
FROMHS
EXCEPTCORRESPONDING(TELEPHONE_ID)
SELECT*
FROMTELVILLE;
Cette requête retourne toutes les lignes de la table HS pour lesquellesTELEPHONE_IDestaussiprésentdanslatableTELVILLE.
LesopérateursJOINLes opérationsUNION,INTERSECT et EXCEPT sont très utiles pourmanipulerplusieurstablesquisontcompatiblespouruneunion.Maisvousallez souvent devoir extraire des données de tables qui ont bien peu de
chosesencommun.Les jointures (JOIN) sontdesopérateurs relationnelstrèspuissantsquipermettentdecombinerdesdonnéesextraitesdeplusieurssources disparates afin de former une table résultat. SQL dispose deplusieurstypesdejointures.Touteladifficultéconsisteàchoisirceluiquicorrespond le mieux au résultat que vous souhaitez obtenir. Nous allonstenterdenousyretrouverdanslessectionsquisuivent.
JointureélémentaireToute requête qui porte sur plusieurs tables est un type de jointure. Lestables sources sont jointes en ce sens que la table résultat contient desinformationsextraitesdetouteslestablessources.LeplussimpledesJOINestunSELECTsansclauseWHEREappliquéàdeuxtables.Chaquelignede la première table est jointe à chaque ligne de la seconde table. Lerésultat est le produit cartésien des deux tables sources. Le nombre delignes que contient la table résultat est égal au nombre de lignes de lapremièretablesourcemultipliéparlenombredelignesdelasecondetablesource.
Imaginons par exemple que vous soyez le DRH d’une société et qu’unepartiedevotretravailconsisteàgérerdesinformationssurlesmembresdupersonnel. La plupart des données qui concernent un employé, commel’adresse de son domicile et son numéro de téléphone, ne sont pasparticulièrementconfidentielles.Maisd’autresdonnées,commesonsalaire,nedoiventêtreconsultéesquepar lespersonnesautorisées.Pourprotégercesinformations,vousallezlesstockerdansunetabledistinctedontl’accèsestprotégéparunmotdepasse.Considérezcesdeuxtables:
EMPLOYESINDEMNITES
------------------
EMP_IDEMPLOYE
PRENOMSALAIRE
NOMPRIMES
VILLE
TELEPHONE
Remplissonslestablesaveccesexemples:
EMP_IDPRENOMNOMVILLETELEPHONE
------------------------------
1WhiteyFordOrange555-1001
2DonLarsonNewark555-3221
3SalMaglieNutley555-6905
4BobTurleyPassaic555-8908
EMPLOYESALAIREPRIMES
---------------------
13300010000
2180002000
3240005000
4220007000
Créezmaintenantunetablerésultatàl’aidedelarequêtesuivante:
SELECT*
FROMEMPLOYES,INDEMNITES;
Cequiproduit:
EMP_IDPRENOMNOMVILLETELEPHONE
EMPLOYESALAIREPRIMES
------------------------------------
-----------------
1WhiteyFordOrange555-10011
3300010000
1WhiteyFordOrange555-10012
180002000
1WhiteyFordOrange555-10013
240005000
1WhiteyFordOrange555-10014
220007000
2DonLarsonNewark555-32211
3300010000
2DonLarsonNewark555-32212
180002000
2DonLarsonNewark555-32213
240005000
2DonLarsonNewark555-32214
220007000
3SalMaglieNutley555-69051
3300010000
3SalMaglieNutley555-69052
180002000
3SalMaglieNutley555-69053
240005000
3SalMaglieNutley555-69054
220007000
4BobTurleyPassaic555-89081
3300010000
4BobTurleyPassaic555-89082
180002000
4BobTurleyPassaic555-89083
240005000
4BobTurleyPassaic555-89084
220007000
La table résultat, qui est le produit cartésien d’EMPLOYES etd’INDEMNITES, contient beaucoup de lignes redondantes. En outre, sasignification n’est pas claire. Elle combine chaque ligne d’EMPLOYESavecchaque ligned’INDEMNITES. Les seules lignes significatives sontcellesquiontunnuméroEMP_IDextraitd’EMPLOYEScorrespondantàunnuméroEMPLOYEprovenantd’INDEMNITES.Danscecasseulement,lenometl’adressed’unemployésontassociésàsonsalaire.
Lorsque vous essayez d’extraire des informations d’une base de donnéesquicontientplusieurs tables, leproduitcartésienretournéparune jointureélémentaire n’est presque jamais ce que vous attendez. Cependant, enappliquant des contraintes aux JOIN avec des clauses WHERE, vous
pouvezéliminertoutesleslignesindésirables.LeJOINlepluscourantquiutiliselaclauseWHEREpourfiltrerestunejointureéquivalente.
EquijointureUnejointureéquivalente(ouéquijointure)estunejointureélémentairedontlaclauseWHEREcontientuneconditionqui spécifiequ’unevaleurd’unecolonne de la première table doit être égale à la valeur de la colonnecorrespondante de la seconde table. En appliquant une équijointure auxtables de l’exemple précédent, vous obtiendrez un résultat bien pluspertinent:
SELECT*
FROMEMPLOYES,INDEMNITES
WHEREEMPLOYES.EMP_ID=INDEMNITES.EMPLOYE;
Cequiproduit:
EMP_IDPRENOMNOMVILLETELEPHONE
EMPLOYESALAIREPRIMES
----------------------------------
-----------------
1WhiteyFordOrange555-1001
13300010000
2DonLarsonNewark55-3221
2180002000
3SalMaglieNutley555-6905
3240005000
4BobTurleyPassaic555-8908
4220007000
Danscettetablederésultat, lessalairesetlesprimesquifigurentàdroitesontassociésauxemployésdontlesnomsfigurentàgauche.Maislatablecontientencorequelquesdonnéesredondantes,carlacolonneEMP_IDestrépétéedanslacolonneEMPLOYES.Vouspouvezrésoudreceproblèmeenreformulantlégèrementlarequête:
SELECT
EMPLOYES.*,INDEMNITES.SALAIRE,INDEMNITES.PRIMES
FROMEMPLOYES,INDEMNITES
WHEREEMPLOYES.EMP_ID=INDEMNITES.EMPLOYE;
Cequiproduit:
EMP_IDPRENOMNOMVILLETELEPHONE
SALAIREPRIMES
----------------------------------
-------------
1WhiteyFordOrange555-1001
3300010000
2DonLarsonNewark555-3221
180002000
3SalMaglieNutley555-6905
240005000
4BobTurleyPassaic555-8908
220007000
Cettetablevousindiquecequevousvoulezsavoirsansvousencombrerdedonnées superflues. Cependant, la requête est quelque peu fastidieuse àécrire,carpourôtertouteambiguïtévousavezpréfixéchaquecolonneparlenomdelatableàlaquelleelleappartient.
Vous pouvez simplifier l’écriture de la requête en utilisant des alias (ounoms de corrélation). Un alias est l’abréviation du nom d’une table. Sivousutilisezdesaliaspourécrirelarequêteprécédente,elleressembleraàceci:
SELECTE.*,I.SALAIRE,I.PRIMES
FROMEMPLOYESE,INDEMNITESI
WHEREE.EMP_ID=I.EMPLOYE;
Dans cet exemple, E est l’alias d’EMPLOYES et I celuid’INDEMNITES.Laportéede l’alias est limitéeà cellede l’instructionoù ilestdéclaré.Une foisquevousavezdéclaréunalias (dans laclause
FROM),vousnedevezplusutiliserquecetaliasdans la requête.Vousnepouvezplusindiqueràlafoisl’aliasetlevrainomdelatable.
L’utilisationsimultanéedunominitialdelatableetdel’aliaspeutinduireenerreur.Considérezlarequêtesuivante:
SELECTT1.C,T2.C
FROMT1T2,T2T1
WHERET1.C>T2.C;
Danscetexemple,l’aliasdeT1estT2et l’aliaspourT2estT1.Bienentendu,définirde tellescorrélationsn’estpas recommandable,mais riennel’interdit.Sivousutilisezenmêmetempslesaliasetlesnomsdestablesdans larequête,vousneserezplusenmesurededistinguer les tablesquevousmanipulez.
L’exempleprécédentéquivautauSELECTsuivant:
SELECTT2.C,T1.C
FROMT1,T2
WHERET2.C>T1.C;
SQLvouspermetd’effectuerlajointuredeplusdedeuxtables.Lenombremaximal de tables que vous pouvez joindre varie d’une implémentation àune autre (mais il est en général plus que suffisant pour couvrir tous vosbesoins).Lasyntaxeutiliséeseprésentedelamanièresuivante:
SELECTE.*,C.SALAIRE,C.PRIMES,Y.TOTAL_VENTES
FROMEMPLOYESE,INDEMNITESC,VENTESY
WHEREE.EMP_ID=C.EMPLOYE
ANDC.EMPLOYE=Y.NOEMP;
Cetteinstructioneffectueuneéquijointuresurtroistablespourproduireunetable résultat qui contient le nom, le montant des ventes et le salaire dechaquecommercial.Ledirecteurdesventespeutainsirapidementjugerdel’adéquationentrelesalaireetlesperformancesd’uncommercial.
Pouraméliorer lesperformanceset la fiabilité, il estconseilléde stockerles ventes effectuées par les commerciaux dans une table distincte de latable EMPLOYES. En effet, les données de la table EMPLOYES sont
relativement statiques. Le nom, le numéro de téléphone et l’adresse d’uncommercial ne changent pas souvent. Par contre, ses résultats sur l’annéesont par essence variables. Comme la table VENTES contient moins decolonnesqu’EMPLOYES,vouspourrezlamettreàjourplusrapidement.Enoutre,celavousépargnerademodifier les informationscontenuesdans latableEMPLOYES.
JointurecroiséeCROSS JOIN est le mot clé pour désigner une jointure élémentairedépourvuedeclauseWHERE.Parconséquent:
SELECT*
FROMEMPLOYES,INDEMNITES;
peutaussis’écrire:
SELECT*
FROMEMPLOYESCROSSJOININDEMNITES;
Lerésultatestleproduitcartésien(égalementappeléproduitvectoriel)desdeuxtablessources.CROSSJOINproduitrarementlerésultatquevousescomptiez,maisc’estuntraitementquiestsouventutilisépoureffectuerunregroupementpréalablededonnéesavantdelesmanipulerpourconstruirelerésultatfinal.
JointurenaturelleUnejointurenaturelleestuncasparticulierd’équijointure.DanslaclauseWHEREd’uneéquijointure,unecolonned’unetablesourceestcomparéeàune colonne d’une seconde table pour déterminer si leurs valeurs sontégales.Cesdeuxcolonnesdoiventêtredemêmetypeetdemêmelongueur,maispeuventporterdesnomsdifférents.Enfait,dansunejointurenaturelle,touteslescolonnesd’unetablequiontlesmêmesnom,typeetlongueurqueles colonnes correspondantes dans la seconde table font l’objet d’unecomparaison.
SupposezquelatableINDEMNITESdel’exempleprécédentcontiennelescolonnes EMP_ID, SALAIRE et PRIMES à la place de EMPLOYE,SALAIRE etPRIMES. Dans ce cas, vous pouvez effectuer une jointurenaturelleentre les tables INDEMNITESetEMPLOYES.LasyntaxedeceJOINseraitlasuivante:
SELECTE.*,I.SALAIRE,I.PRIMES
FROMEMPLOYESE,INDEMNITESI
WHEREE.EMP_ID=I.EMP_ID;
Cetterequêteestunejointurenaturelle.Vouspouvezaussiutiliserlasyntaxesuivante:
SELECTE.*,I.SALAIRE,I.PRIMES
FROMEMPLOYESENATURALJOININDEMNITESI;
CetterequêteeffectuelajointuredeslignesoùE.EMP_ID=I.EMP_ID,oùI.SALAIRE=C.SALAIRE, et où I.PRIMES =C.PRIMES. La table résultatcontiendra seulement les lignes dont toutes les colonnes auront descorrespondances.Danscetexemple,lerésultatdecesrequêtesestlemêmecarlatableEPLOYEnecontientnicolonneSalairenicolonnePrime.
JointureconditionnelleUne jointure conditionnelle est une équijointure, à ceci près que laconditiondetestn’estpasl’égalité(bienquecepuisseêtrelecas),maisunprédicat.Silaconditionestsatisfaiteparuneligne,celle-ciestintégréeàlatablerésultat.Lasyntaxeemployéeestlégèrementdifférentedecequevousavezpuvoirjusqu’àprésent.LaconditionestcontenuedansuneclauseONetnonplusdansuneclauseWHERE.
Supposonsqu’unstatisticiendubase-balldésireidentifierleslanceursdelaLigue nationale qui ont participé au même nombre de parties complètesqu’unouplusieursdeslanceursdelaLigueaméricaine.Cettequestionpeutêtre résolue avec une jointure équivalente, mais aussi avec une jointureconditionnelle:
SELECT*
FROMNATIONALEJOINAMERICAINE
ONNATIONALE.PARTIES_COMPLETES=
AMERICAINE.PARTIES_COM-
PLETES;
JointureparnomdecolonneUne jointure par nom de colonne est une jointure naturelle très soupled’utilisation.Lorsd’unejointurenaturelle,touteslescolonnesquiportentlemêmenomdans les tables sources sont comparées entre elles pour testerleur égalité. Avec une jointure par nom de colonne, il est possible despécifierlescolonneshomonymesquidoiventêtrecomparéesetcellesquinedoiventpasl’être.Vouspouvezchoisirtouteslescolonnes,faisantainside cette jointure par nom de colonne une jointure naturelle. Vous pouvezégalement ne spécifier que quelques colonnes homonymes, ce qui vouspermettradecontrôlerfinementleslignesquiapparaîtrontdansvotretablerésultat.
Supposonsquevoussoyezunfabricantd’échiquiersetquevousdisposiezd’unetabled’inventairepourgérervotrestockdepiècesblanches,etd’uneautretableconcernantquantàellevotrestockdepiècesnoires.Cestablescontiennentlesdonnéessuivantes:
BLANCNOIR
----------
PièceQuantBoisPièceQuant
Bois
---------------------------
---
Roi502ChêneRoi502
Ebène
Reine398ChêneReine397
Ebène
Pion1020ChênePion1020
Ebène
Fou985ChêneFou985
Ebène
Cavalier950ChêneCavalier950
Ebène
Tour431ChêneTour453
Ebène
Pourchaquetypedepièce,lenombredepiècesblanchesdevraitêtreégalau nombre de pièces noires. Si ce n’est pas le cas, des échiquiers sontincomplets.Lespiècesontpuêtreperduesouvolées.Danstouslescas,desmesuresdecontrôles’imposent.
Une jointure naturelle teste l’égalité de toutes les colonnes homonymes.Dansnotreexemple,latablerésultatnecontiendrarien,caraucunelignedela colonneBOIS de la table BLANC ne correspond à une ligne de lacolonneBOISdelatableNOIR.Cettetablerésultatnevouspermetpasdesavoirsidespiècessontmanquantes.EffectuezplutôtunejointureparnomdecolonneenexcluantlacolonneBOIS.Larequêtepeutprendrelaformesuivante:
SELECT*
FROMBLANCJOINNOIR
USING(PIECE,QUANT);
La table résultat ne contient que les lignes pour lesquelles le nombre depiècesblanchesestégalaunombredepiècesnoires.
PièceQuantBoisPièceQuantBois
------------------------------
Roi502ChêneRoi502Ebène
Pion1020ChênePion1020Ebène
Fou985ChêneFou985Ebène
Cavalier950ChêneCavalier950Ebène
Lapersonnequi gère les stockspourradéduirede cette listequ’il y aunproblèmeaveclesreinesetlestours.
JointureinterneVousenêtesprobablement au stadeoùvouspensezque les jointures sontune affaire plutôt ésotérique, et qu’il faut un haut degré de discernementspirituel pour s’en servir correctement.Vous avez peut-être aussi entenduparler de la mystérieuse jointure interne, ce qui vous a plongé dans uneprofonderéflexionsurl’essencemêmedesopérationsrelationnellesetleursrapportséventuelsavecd’anciennespratiqueschamaniques...
Enfait,cettejointuren’ariendemystérieux.Touteslesjointuresprésentéesdanscechapitresontdesjointuresinternes.J’auraispuqualifierlajointureparnomdecolonnedel’exempleprécédentdejointureinterneenutilisantlasyntaxesuivante:
SELECT*
FROMBLANCINNERJOINNOIR
USING(PIECE,QUANT);
Lerésultatobtenuauraitétéexactementlemême.
Toutsimplement,lajointureinterneestainsiappeléepourladistinguerdela jointureexterne.Une jointure internesupprime toutes les lignesdans latable résultat qui ne correspondent pas àdes lignes équivalentesdans lesdeuxtablessources.Lajointureexterneconserveceslignes.C’estlàtouteladifférence!Iln’yadoncriendemétaphysiquedanscetteaffaire.
JointureexterneLorsque vous effectuez la jointure de deux tables, la première (à gauche)peutcontenirdeslignessanséquivalentdanslasecondetable(àdroite).Delamêmemanière,latablededroitepeutcontenirdeslignessanséquivalentdanslatabledegauche.Sivouseffectuezunejointureinternesurcestables,toutesleslignessanscorrespondanceserontexcluesdurésultat.Parcontre,une jointure externe les conservera. Il existe trois types de jointuresexternes:lajointureexternegauche,lajointureexternedroiteetlajointureexternecomplète.
Jointureexternegauche
Dansunerequêtequicontientunejointure,latabledegaucheestcellequiprécèdelemotcléJOIN,etlatablededroitecellequilesuit(maisvousavieztrouvé!).Unejointureexternegaucheconserveleslignesdelatabledegauchequin’ontpasd’équivalent,maisellesupprimecellesdelatablededroitequisontdanslemêmecas.
Pour mieux comprendre les jointures externes, prenons l’exemple d’unebase de données contenant des informations sur les employés, lesdépartements et les sites d’une entreprise. Les Tableaux 11.1,11.2et11.3contiennentquelquesexemplesdedonnées.
TABLEAU11.1LatableSITES.
SITE_ID VILLE
1 Boston
3 Tampa
5 Chicago
Supposonsmaintenantquevoussouhaitiezvisualisertouteslesinformationsrelativesauxemployés,ycomprisleurdépartementetleursite.Vouspouvezobtenirlerésultatvouluavecuneéquijointure:
TABLEAU11.2LatableDEPARTEMENTS.
DEPT_ID SITE_ID NOM
21 1 Ventes
24 1 Admin
27 5 Réparation
29 5 Stock
TABLEAU11.3LatableEMPLOYES.
EMP_ID DEPT_ID NOM
61 24 Kirk
63 27 McCoy
SELECT*
FROMSITESS,DEPARTEMENTSD,EMPLOYESE
WHERES.SITE_ID=D.SITE_ID
ANDD.DEPT_ID=E.DEPT_ID;
Cetteinstructionproduitlerésultatsuivant:
1Boston241Admin6124Kirk
5Chicago275Reparation6327McCoy
Latable résultatcontient toutes lesdonnéesrelativesà tous lesemployés,dont le site et le département où ils travaillent. L’équijointure fonctionne,cartouslesemployéstravaillentsurunsitedansuncertaindépartement.
Supposonsmaintenantquevoussouhaitiezobtenirdesinformationssurlessites.Leproblèmeestdifférent,carunsitepeut trèsbiennepasavoirdedépartement. Pour obtenir le résultat escompté, vous devez utiliser unejointureexternetelleque:
SELECT*
FROMSITESSLEFTOUTERJOINDEPARTEMENTSD
ON(S.SITE_ID=D.SITE_ID)
LEFTOUTERJOINEMPLOYESE
ON(D.DEPT_ID=E.DEPT_ID);
La jointure extrait des données des trois tables. Tout d’abord, la tableSITESest jointeà la tableDEPARTEMENTS.Puis la table résultat est àsontourjointeàlatableEMPLOYES.Leslignesdelatablequisetrouveàgauchedel’opérateurLEFTOUTERJOINetquin’ontpasd’équivalentdans la tableplacéeàdroitede l’opérateur sont inclusesdans le résultat.Parconséquent,lorsdecettepremièrejointure,touslessitessontinclus,ycompris ceux qui ne sont pas associés à des départements. Lors de la
secondejointure,touslesdépartementssontinclus,mêmesiaucunemployén’yestattaché.Lerésultatestlesuivant:
1Boston241Admin6124Kirk
5Chicago275Reparation6327McCoy
3TampaNULLNULLNULLNULLNULLNULL
5Chicago295StockNULLNULLNULL
1Boston211VentesNULLNULLNULL
Lesdeuxpremièreslignessontidentiquesàcellesdel’exempleprécédent.Les colonnes qui correspondent au département et à l’employé de latroisième ligne (3 Tampa) contiennent des valeurs nulles, car aucundépartement n’est défini à Tampa et aucun employé n’y travaille. Lesquatrième et cinquième lignes (5 Chicago et 1 Boston) contiennent desinformations sur les départements Ventes et Stock, mais la colonne«Employés»yprendunevaleurnulle,caraucunepersonnen’estrattachéeà ces deux départements. La jointure externe vous fournit tout ce que lajointureéquivalentevousdonnait,plus:
» Touslessitesdelasociété,qu’ilspossèdentounonun
département.
» Touslesdépartementsdelasociété,qu’ilsdisposentou
nond’employés.
Les lignes retournées dans l’exemple précédent n’apparaissent pasforcément dans l’ordre que vous souhaitez. Cet ordre peut varier d’uneimplémentationàuneautre.Pourvousassurerqueleslignesretournéessontclasséescommevousledésirez,ajoutezuneclauseORDERBYdansvotreinstructionSELECT,commececi:
SELECT*
FROMSITESSLEFTOUTERJOINDEPARTEMENTSD
ON(S.SITE_ID=D.SITE_ID)
LEFTOUTERJOINEMPLOYESE
ON(D.DEPT_ID=E.DEPT_ID)
ORDERBYS.SITE_ID,D.DEPT_ID,E.EMP_ID;
Une jointure externe gauche peut également s’écrireLEFTJOIN, car iln’existepasdejointureinternegauche.
JointureexternedroiteIl n’y a plus qu’à intervertir les équipes... La jointure externe droitepréservedanslatablededroiteleslignessanséquivalentdanslatabledegauche, et inversement supprime de la table de gauche les lignes sanséquivalent dans la table de droite. Vous pouvez l’utiliser sur les mêmestablesetobtenir lesmêmesrésultatsen inversantsimplement l’ordredanslequelvousindiquezlestableslorsdelajointure.
SELECT*
FROMEMPLOYESERIGHTOUTERJOINDEPARTEMENTS
D
ON(D.DEPT_ID=E.DEPT_ID)
RIGHTOUTERJOINSITESS
ON(S.SITE_ID=D.SITE_ID);
Danscetteformule,lapremièrejointureproduitunetablequicontienttouslesdépartements, qu’ils aientounonunemployé.La secondeproduit unetablequicontienttouslessites,qu’ilsdisposentounond’undépartement.
Unejointureexternedroitepeutégalements’abrégerenRIGHTJOIN,cariln’existepasdejointureinternedroite.
JointureexternecomplèteLa jointure externe complète est une combinaison de jointure externegauche et de jointure externe droite. Elle retient les lignes sanscorrespondanceàlafoisdanslestablesdegaucheetdedroite.Reprenonsl’exempleprécédent.Notresociétépeutavoir:
» Dessitessansdépartements.
» Desdépartementssanssite.
» Desdépartementssansemployés.
» Desemployéssansdépartement.
Pour afficher tous les sites, départements et employés, que leurs lignesdisposentounondeligneséquivalentesdanslesautrestables,utilisezunejointureexternecomplètesouslaformesuivante:
SELECT*
FROMSITESSFULLJOINDEPARTEMENTSD
ON(S.SITE_ID=D.SITE_ID)
FULLJOINEMPLOYESE
ON(D.DEPT_ID=E.DEPT_ID);
Une jointure externe complète peut également s’abréger enFULLJOIN,cariln’existepasdejointureinternecomplète.
Jointured’unionContrairementauxautrestypesdejointure,lajointured’unionn’essaiepasdecomparerune lignede la tablesourcedegaucheaux lignesde la tablesource de droite. Elle crée une nouvelle table virtuelle qui contient lerésultatdel’uniondescolonnesdesdeuxtablessources.
Danslatablevirtuellerésultat,lescolonnesextraitesdelatablesourcedegauchecontiennenttoutesleslignesquisetrouvaientdanscettetable.Dansceslignes,lescolonnesextraitesdelatablededroiteprennentdesvaleursnulles. De même, les colonnes extraites de la table source de droitecontiennent toutes les lignes qui se trouvaient dans cette table, et, danschacunedeceslignes,lescolonnesextraitesdelatabledegaucheprennentlavaleurnulle.Ainsilatablerésultatd’unejointureunionreprendtouteslescolonnesdesdeux tables sources, et laquantitéde lignesqu’elle contientestégaleàlasommedunombredeslignesdesdeuxtablessources.
Lerésultatd’unejointured’unionn’estpasimmédiatementutilisabledanslaplupart des cas, la table produite contenant généralement de nombreusesvaleurs nulles. Cependant, vous pouvez utiliser cette table avecl’expression COALESCE (voyez le Chapitre 9) pour récupérer desinformationsintéressantes.Prenonsunexemple.
Supposonsquevoustravailliezpourunesociétéquiconçoitetconstruitdesfusées expérimentales. Vous menez de front plusieurs projets. Vouscollaborez avec des ingénieurs dont les compétences sont multiples. Enqualité de responsable, vous voulez savoir qui sont ces ingénieurs, dequelles compétences ils disposent et sur quels projets ils travaillent.Actuellement,cesinformationssontrépartiesentrelestablesEMPLOYES,PROJETSetCOMPETENCES.
La tableEMPLOYEScontientdesdonnéessur lespersonnelsetEMP_IDestsacléprimaire.LatablePROJETScontientunelignepourchaqueprojetauquelunemployéaparticipé.PROJETS.EMP_IDestunecléétrangèrequifaitréférenceàlatableEMPLOYES.LatableCOMPETENCESdécritles compétences de chaque employé.COMPETENCES.EMP_ID est unecléétrangèrequiréférencelatableEMPLOYES.
La tableEMPLOYEScontientexactementune lignepourchaqueemployé.LestablesPROJETSetCOMPETENCESontzéroouplusieurslignes.
LesTableaux11.4,11.5 et 11.6présentent des exemples dedonnéespourcestroistables.
TABLEAU11.4LatableEMPLOYES.
EMP_ID NOM
1 Ferguson
2 Frost
3 Toyon
TABLEAU11.5LatablePROJETS.
NOM_PROJET EMP_ID
X-63 Structure1
X-64 Structure1
X-63 Guidage2
X-64 Guidage2
X-63 Télémétrie3
X-64 Télémétrie3
TABLEAU11.6LatableCOMPETENCES.
COMPETENCE EMP_ID
Conceptionmécanique 1
Aérodynamique 1
Conceptionanalogique 2
Gyroscope 2
Conceptionnumérique 3
ConceptionR/F 3
À la lecturedeces tableaux,vousapprenezqueFergusona travaillé à laconstruction des structures des X-63 et X-64, et qu’il est un expert enconceptionmécaniqueetenaérodynamique.
Voussouhaitezmaintenantvisualisertouteslesinformationsrelativesàtousles employés. Vous décidez d’appliquer une équijointure aux tablesEMPLOYES,PROJETSetCOMPETENCES.
SELECT*
FROMEMPLOYESE,PROJETSP,COMPETENCESC
WHEREE.EMP_ID=P.EMP_ID
ANDE.EMP_ID=C.EMP_ID;
Vouspouvezexprimercettemêmeopérationenutilisantunejointureinternedelamanièresuivante:
SELECT*
FROMEMPLOYESEINNERJOINPROJETSP
ON(E.EMP_ID=P.EMP_ID)
INNERJOINCOMPETENCESC
ON(E.EMP_ID=C.EMP_ID);
Les deux formulations donnent le même résultat, celui qui est représentédansleTableau11.7.
TABLEAU11.7Résultatdelajointureinterne.
E.EMP_
ID
E.NOM P.EMP_
ID
P.NOM_
PROJET
C.EMP_ID C.COMPETENCE
1 Ferguson 1 X-63
Structure
1 Conception
mécanique
1 Ferguson 1 X-63
Structure
1 Aérodynamique
1 Ferguson 1 X-64
Structure
1 Conception
mécanique
1 Ferguson 1 X-64
Structure
1 Aérodynamique
2 Frost 2 X-63
Guidage
2 Conception
analogique
2 Frost 2 X-63
Guidage
2 Gyroscope
2 Frost 2 X-64
Guidage
2 Conception
analogique
2 Frost 2 X-64
Guidage
2 Gyroscope
3 Toyon 3 X-63
Télémétrie
3 Conception
numérique
3 Toyon 3 X-63
Télémétrie
3 ConceptionR/F
3 Toyon 3 X-64
Télémétrie
3 Conception
numérique
3 Toyon 3 X-64
Télémétrie
3 ConceptionR/F
Cesdonnéesnevousapprennentpasgrand-chose.Lesnuméros identifiantles employés apparaissent quatre fois chacun et les lignes relatives auxcompétencesd’unemployésontdupliquées.La jointure internen’estdoncpas particulièrement adaptée pour répondre à ce type de question. Vouspouvez obtenir un meilleur résultat en utilisant une jointure d’unioncombinée à quelques instructions SELECT soigneusement choisies.Commençonsparunejointured’uniondebase:
SELECT*
FROMEMPLOYESEUNIONJOINPROJETSP
UNIONJOINCOMPETENCESC;
Remarquez l’absence de clauseON. La jointure d’union ne filtre pas lesdonnées. C’est pourquoi cette clause n’est pas nécessaire. L’instructionproduitlerésultatreprésentédansleTableau11.8.
TABLEAU11.8RésultatdeUNIONJOIN.
E.EMP_
ID
E.NOM P.EMP_ID P.NOM_PROJET C.EMP_ID C.COMPETENCE
1 Ferguson NULL NULL NULL NULL
NULL NULL 1 X-63Structure NULL NULL
NULL NULL 1 X-64Structure NULL NULL
NULL NULL NULL NULL 1 Conception
mécanique
NULL NULL NULL NULL 1 Aérodynamique
2 Frost NULL NULL NULL NULL
NULL NULL 2 X-63Guidage NULL NULL
NULL NULL 2 X-64Guidage NULL NULL
NULL NULL NULL NULL 2 Conception
analogique
NULL NULL NULL NULL 2 Gyroscope
3 Toyon NULL NULL NULL NULL
NULL NULL 3 X-63
Télémétrie
NULL NULL
NULL NULL 3 X-64
Télémétrie
NULL NULL
NULL NULL NULL NULL 3 Conception
numérique
NULL NULL NULL NULL 3 ConceptionR/F
Chaquetableaétéétendueversladroiteouverslagaucheavecdesvaleursnulles, et les lignes ainsi étendues ont été réunies.Notez que l’ordre deslignesestarbitraireetdépenddel’implémentation.Vouspouvezmaintenantorganiserlesdonnéessousuneformeplusexploitable.
Remarquez que la table comporte trois colonnes ID dont une seule necontient pas de valeur nulle dans chaque ligne. Vous pouvez améliorerl’affichageenfusionnantcescolonnesID.Commejel’aiditauChapitre9,l’expressionCOALESCEsélectionnelapremièrevaleurnonnulledansune
liste. Ici, nous allons lui demander de prendre la valeur du seul numérod’identificationnonnuldanslalistedecolonnesquiluiestfournie:
SELECTCOALESCE(E.EMP_ID,P.EMP_ID,C.EMP_ID)AS
ID,
E.NOM,P.NOM_PROJET,C.COMPETENCES
FROMEMPLOYESEUNIONJOINPROJETSP
UNIONJOINCOMPETENCESC
ORDERBYID;
LaclauseFROMestlamêmequedanslesexemplesprécédents,maisvousfusionnez les trois colonnesEMP_ID en une seule colonne appelée ID.Vous triez le résultat selon ID. Le Tableau 11.9 vous montre le résultatobtenu.
TABLEAU11.9Résultatdelajointured’unionavecl’expressionCOALESCE.
ID E.NOM P.NOM_PROJET C.COMPETENCE
1 Ferguson X-63Structure NULL
1 Ferguson X-64Structure NULL
1 Ferguson NULL Conceptionmécanique
1 Ferguson NULL Aérodynamique
2 Frost X-63Guidage NULL
2 Frost X-64Guidage NULL
2 Frost NULL Conceptionanalogique
2 Frost NULL Gyroscope
3 Toyon X-63Télémétrie NULL
3 Toyon X-64Télémétrie NULL
3 Toyon NULL Conceptionnumérique
3 Toyon NULL ConceptionR/F
SELECTCOALESCE(E.EMP_ID,P.EMP_ID,C.EMP_ID)AS
ID,
E.NOM,COALESCE(P.TYPE,C.TYPE)ASTYPE,
Chacunedeslignesdecerésultatcontientdesdonnéesrelativesàunprojetouàunecompétence,maispasauxdeuxàlafois.Pourlirecerésultat,vousdevez tout d’abord déterminer de quoi parle chaque ligne (projet oucompétence). Si la colonne NOM_PROJET ne contient pas une valeurnulle, la ligne correspond à unprojet. Si la colonneCOMPETENCESnecontientpasunevaleurnulle,lalignecorrespondàunecompétence.
Vous pouvez clarifier ce résultat en ajoutant une autre expressionCOALESCEàl’instructionSELECT,commesuit:
NOM_PROJET,C.COMPETENCES
FROMEMPLOYESE
UNIONJOIN(SELECT“Projet”ASTYPE,P.*
FROMPROJETS)P
UNIONJOIN(SELECT“Compétence”ASTYPE,C.*
FROMCOMPETENCES)C
ORDERBYID,TYPE;
Danslajointured’union,latablePROJETSestremplacéeparunSELECTimbriquéquirajouteunecolonneappeléeP.TYPE,dontlavaleurconstanteest«Projet»,auxcolonnesprovenantdelatablePROJETS.Demême,la tableCOMPETENCESa été remplacéeparunSELECT imbriqué quirajoute une colonne appelée C.TYPE, dont la valeur constante est«Compétence», aux colonnes extraites de la tableCOMPETENCES.Dans chaque ligne, donc,P.TYPE est soit nulle, soit «Projet », etC.TYPEestsoitnulle,soit«Compétence».
LeSELECTexterneutiliseCOALESCEpourfusionnercesdeuxcolonnestypes en une seule appeléeTYPE. Vous spécifiez ensuiteTYPE dans laclauseORDERBYafindetrierleslignesquiontlemêmeIDpour faireapparaîtred’abordlesprojets,puislescompétences.LerésultatestmontrédansleTableau11.10.
TABLEAU11.10Résultatsaffinésdelajointured’unionavecdesexpressions
COALESCE.
ID E.NOM TYPE NOM_PROJET COMPETENCE
1 Ferguson Projet X-63Structure NULL
1 Ferguson Projet X-64Structure NULL
1 Ferguson Compétences NULL Conceptionmécanique
1 Ferguson Compétences NULL Aérodynamique
2 Frost Projet X-63Guidage NULL
2 Frost Projet X-64Guidage NULL
2 Frost Compétences NULL Conceptionanalogique
2 Frost Compétences NULL Gyroscope
3 Toyon Projet X-63Télémétrie NULL
3 Toyon Project X-64Télémétrie NULL
3 Toyon Compétences NULL Conceptionnumérique
3 Toyon Compétences NULL ConceptionR/F
Latablerésultatcontientmaintenantunexposétrèslisibledescompétenceset des projets sur lesquels ont travaillé les employés enregistrés dans latableEMPLOYES.
Étant donné le grand nombre d’opérations de jointure qu’il est possibled’effectuer,établirdes liensentredifférentes tablesnedevraitpasêtreun
problèmequellequesoitleurstructure.Àpartirdumomentoùlesdonnéesexistent dans votre base, SQL vous permettra de les retrouver et de lesaffichersousuneformesignificative.
ONetWHERELafonctiondesclausesONetWHEREdanslesdifférentstypesdejointurepeutprêter à confusion.Cesdifférentspointsdevraientvouspermettredeclarifierlasituation:
» LaclauseONs’utilisedansdesjointuresinterne,gauche,
droiteetcomplète.Lesjointurescroiséesetunionne
comportentpasdeclauseON,caraucuned’entreellesne
filtrelesdonnées.
» LaclauseONdansunejointureinterneestl’équivalent
logiquedelaclauseWHERE.Laconditionénoncéepourrait
êtrespécifiéeavecuneclauseONouuneclauseWHERE.
» LaclauseONjouedanslesjointuresexternes(gauche,
droiteetcomplète)unrôledifférentdesclausesWHERE.
WHEREnefiltrequeleslignesretournéesparlaclause
FROM.Leslignesrejetéesparlefiltrenesontpasincluses
danslerésultat.Àl’inverse,laclauseONfiltred’abordles
lignesissuesduproduitcartésien,puislesinclutdansle
résultatenlesétendantéventuellementàl’aidedevaleurs
nulles.
L
Chapitre12Effectuerdesrecherchesapprofondiesavecdesrequêtesimbriquées
DANSCECHAPITRE:
» ExtrairedesdonnéesdeplusieurstablesavecuneseuleinstructionSQL.
» Comparerunevaleurd’unetableavecunensembledevaleursd’uneautretable.
» UtiliserSELECTpourcomparerunevaleurd’unetableavecunevaleurd’uneautretable.
» Comparerunevaleurd’unetableavectouteslesvaleurscorrespondantesd’uneautretable.
» Créerdesrequêtesquimettentencorrélationdeuxlignescorrespondantesdansdestables.
» Déterminerleslignesàmettreàjour,àsupprimerouàinsérerenutilisantunesous-requête.
’une desmeilleuresméthodes pour protéger l’intégrité de vos donnéesestdenormaliservotrebasededonnées,cequipréviendral’apparitiond’anomalie lorsdesmodifications.Lanormalisationconsisteàdiviser
unetableenplusieursautrestables,chacunetraitantd’unthèmeparticulier.
Par exemple, vous n’allez pasmélanger des informations sur les produitsavecdesinformationssurlesclientsauseind’unemêmetable,mêmesilesclients ont acheté des produits. Si vous normalisez une base de donnéescorrectement, les données seront réparties entre des tables multiples. Laplupartdesrequêtesquevouseffectuerezalorsdevrontextrairedesdonnées
dedeuxouplusieurstables.Pourcela,vousutiliserezunejointureoul’undes opérateurs relationnels (UNION, INTERSECT ou EXCEPT). Cesopérateursextraientdesinformationsdeplusieurstablesetlescombinentenuneseuletable.
Une autre solution pour extraire des données de deux ou plusieurs tablesconsisteàutiliserdesrequêtesimbriquées.EnSQL,unerequêteimbriquéeestunerequêteoùune instructionexternecontientunesous-requête. Cettesous-requêtepeutelle-mêmeincorporeruneautresous-requêtedeplusbasniveau. Le nombre de requêtes que vous pouvez ainsi imbriquer est enthéorie infini, mais il est dans la pratique limité par certainesimplémentations.
Les sous-requêtes sont invariablement des instructionsSELECT,mais lesinstructions qui les incluent peuvent aussi être une opération INSERT,UPDATEouDELETE.
Comme une sous-requête est parfaitement capable de traiter une tabledifférente de celle sur laquelle porte l’instruction qui la contient, lesrequêtesimbriquéessontunexcellentmoyenpourextrairedesinformationsprovenantdemultiplestables.
Supposonspar exemplequevous interrogiez labasededonnéesdevotresociété pour trouver tous les responsables commerciaux âgés de plusde 50 ans. Si vous utilisez les jointures (étudiées au Chapitre 11), votrerequêtepourraseprésenterainsi:
SELECTD.NODEPT,D.NOM,E.NOM,E.AGE
FROMDEPTD,EMPLOYESE
WHERED.RESPONSABLE_ID=E.IDANDE.AGE>50
;
Destl’aliasdelatableDEPTetEl’aliasdelatableEMPLOYES.CettedernièrecontientunecolonneIDquijouelerôledecléprimaire,tandisquelatableDEPTpossèdeunecolonneRESPON-SABLE_IDdont lavaleurest celle del’IDde l’employé responsable du département. J’emploieuneseulejointure(lalistedestablesdelaclauseFROM)pourcouplerlestables, etunWHEREpour filtrer toutes les lignesà l’exceptiondecellesqui correspondent aux critères.Remarquezque la liste des paramètres de
l’instruction SELECTmentionne les colonnes NODEPT et NOM de latableDEPT,etlescolonnesNOMetAGEdelatableEMPLOYES.
Supposonsmaintenantquevoussouhaitiezrécupérerlemêmeensembledelignes,maisenvouslimitantauxcolonnesdelatableDEPT.Autrementdit,vousvoulezobtenirlalistedesdépartementsdontleresponsableestâgédeplus de 50 ans, mais l’identité et l’âge exact des personnes ne vousintéressentpas.Vouspouvezreformulerlarequêteenremplaçantlajointureparunesous-requête:
SELECTD.NODEPT,D.NOM
FROMDEPTD
WHEREEXISTS(SELECT*FROMEMPLOYESE
WHEREE.ID=D.RESPONSABLEIDANDE.AGE>
50);
Cetterequêtecontientdeuxnouveauxéléments:lemotcléEXISTSet leSELECT * dans la clause WHERE. Le second SELECT est une sous-requête(ousous-sélection),etlemotcléEXISTSest l’undesnombreuxoutilsquevouspouvezutiliserdansunesous-requête.
Quefaitunesous-requête?Les sous-requêtes se trouvent généralement dans la clause WHERE del’instructionquilesenglobe.Leurfonctionconsisteàspécifierlescritèresde recherche de la clause WHERE. Différents types de sous-requêtesproduirontdifférentsrésultats.Certainesrenvoientunelistedevaleursquel’instruction externe utilise comme entrée. D’autres retournent une uniquevaleur que l’instruction englobante évalue à l’aide d’un opérateur decomparaison.Un troisième typede sous-requêteproduitunevaleurTrueouFalse.
Requêtesimbriquéesretournantunensembledelignes
Pour illustrer comment une requête imbriquée retourne un ensemble delignes, supposons que vous travailliez pour un intégrateur de matérielinformatique. Votre société, Zetec Corporation, assemble des systèmes àpartirdecomposantsachetés,puisvendcessystèmesàdessociétésoudesadministrations. Cette activité est décrite dans une base de donnéesrelationnelle. Elle contient de nombreuses tables, mais nous ne nousintéresserons qu’à trois d’entre elles : PRODUITS, COMP_UTI-LISES,COMPOSANTS. La table PRODUITS (voir le Tableau 12.1) contient lalistedetouslesproduitsquevousproposez.LatableCOMPOSANTS(voirleTableau12.2)regroupelalistedetouslescomposantsquevousutilisez.La table COMP_UTILISES (voir Tableau 12.3) précise les composantsutilisésdanschaqueproduit.Cestablessontdéfiniescommesuit:
Un composant peut être utilisé dans plusieurs produits et un produit peutcontenirplusieurscomposants (relationplusieursàplusieurs), cequipeutengendrer des problèmes d’intégrité. Pour contourner cette difficulté, latable de liaison COMP_UTI-LISES permet de relier les tablesCOMPOSANTS et PRODUITS. Un composant peut apparaître dansplusieurs lignes de COMP_ UTILISES, mais chaque ligne deCOMP_UTILISES ne référence qu’un seul composant (relation un àplusieurs). Demême, un produit peut apparaître dans plusieurs lignes deCOMP_UTI-LISES,mais chaque ligne deCOMP_UTILISES ne référencequ’unseulproduit(autrerelationunàplusieurs).Enajoutantcettetabledeliaison, une relation plusieurs à plusieurs a été transformée en deuxrelations un à plusieurs. Cette réduction de complexité de relation est unexempledenormalisation.
Lessous-requêtesintroduitesparlemotcléINUnedesformesdesous-requêteimbriquéecompareunevaleuruniqueàunensemble de valeurs retournées parSELECT. Elle fait appel au prédicatIN,selonlasyntaxesuivante:
SELECTliste_colonnes
FROMtable
WHEREexpressionIN(sous-requête);
TABLEAU12.1LatablePRODUITS.
Colonne Type Contraintes
MODELE Char(6) PRIMARYKEY
NOM_PROD Char(35)
DESC_PROD Char(31)
PRIX Numeric(9,2)
TABLEAU12.2LatableCOMPOSANTS.
Colonne Type Contraintes
COMP_ID CHAR(6) PRIMARYKEY
TYPE_COMP CHAR(10)
DESC_COMP CHAR(31)
TABLEAU12.3LatableCOMP_UTILISES.
Colonne Type Contraintes
MODELE CHAR(6) FOREIGNKEY(pourPRODUITS)
COMP_ID CHAR(6) FOREIGNKEY(pourCOMPOSANTS)
L’évaluationdel’expressionquiFiguredanslaclauseWHEREproduitunevaleur.Sicettedernièreappartientàlalisteretournéeparlasous-requête,la clause WHERE retourne une valeur Vrai, et les colonnes de la lignetraitée sont ajoutées au résultat. La sous-requête peut référencer lamêmetablequelarequêteexterneouuneautretable.
La base de données de Zetec illustre l’utilisation de ce type de requête.Supposez que l’industrie informatique soit frappée par une pénurie demoniteurs.Sivotrestockestépuisé,vousneserezplusenmesuredelivrerlesproduitsquicomportentdesécrans.Vousvoulezdoncsavoirquelssontcesproduits.Saisissezlarequêtesuivante:
SELECTMODELE
FROMCOMP_UTILISES
WHERECOMP_IDIN
(SELECTCOMP_ID
FROMCOMPOSANTS
WHERETYPE_COMP=‘Moniteur’);
SQLexécutelarequêtelaplusimbriquéeenpremier,c’est-à-direcellequiretourne la valeur de COMP_ID de chaque ligne de la tableCOMPOSANTSoùleTYPE_COMPest‘Moniteur’.Lerésultatestunelistedesnumérosd’identificationdetouslesmoniteurs.Larequêteexternecompare ensuite la valeur du COMP_ID de chaque ligne de la tableCOMP_UTILISES aux valeurs de cette liste. Si la comparaison estvalidée, la valeur de la colonneMODELEde cette ligne est ajoutée à latablerésultatproduiteparleSELECTexterne.Lerésultatfinalestunelistede tous les produits qui comportent un moniteur. L’exemple suivant vousmontrecequisepasselorsdel’exécutiondecetterequête:
MODELE
------
CX3000
CX3010
CX3020
MB3030
MX3020
MX3030
Vousconnaissezmaintenantlesproduitspourlesquelsvousserezbientôtenrupturedestock.
Sivousutilisezcetteformed’imbrication,lasous-requêtedoitspécifieruneseulecolonne,et le typededonnéedecettecolonnedoitcorrespondreautypedel’argumentprécédantlemotcléIN.
Lessous-requêtesintroduitesparlemot
cléNOTINVouspouveztoutaussibienintroduireunesous-requêteaveclemotcléNOTIN.Enutilisant la requêtedécritedans lasectionprécédente, ladirectiondeZetec a identifié les produits qui ne peuvent plus être commercialisésfaute de moniteurs. C’est intéressant, mais pas très efficace sur le plancommercial.Elleveutdoncmaintenantsavoirquelssontlesproduitsquinecomportent pas de moniteur afin de renforcer leur vente. Une requêteimbriquéecomportantunesous-requête introduitepar lemotcléNOTINfourniralerésultatescompté:
SELECTMODELE
FROMCOMP_UTILISES
WHEREMODELENOTIN
(SELECTCOMP_ID
FROMCOMPOSANTS
WHERETYPE_COMP=‘Moniteur’));
Cetterequêteproduitlerésultatsuivant:
MODELE
------
PX3040
PB3050
PX3040
PB3050
Notezquelatablerésultatcontientdesentréesdupliquées.Cetteduplicationestdueaufaitqu’unproduitcontenantplusieurscomposantsautresquedesmoniteurs possède une ligne dans la table COMP_UTILISE pour chaquecomposant utilisé. La requête crée une entrée dans la table résultat pourchacunedeceslignes.
Danscetexemple,lenombredelignesnecréepasdeproblème,carlatablerésultat est de taille réduite. Mais cette table pourrait contenir descentaines, voire des milliers de lignes. Vous devriez alors éliminer lesdoublons.Pourcela,ajoutezdanslarequêtelemotcléDISTINCT.Seules
leslignesdistinctes(différentes)detoutescellesquiontdéjàétérécupéréesserontajoutéesàlatablerésultat:
SELECTDISTINCTMODELE
FROMCOMP_UTILISES
WHEREMODELENOTIN
(SELECTCOMP_ID
FROMCOMPOSANTS
WHERETYPE_COMP=‘Moniteur’));
Commeprévu,lerésultatestlesuivant:
MODELE
------
PX3040
PB3050
RequêtesimbriquéesretournantuneseulevaleurL’introduction d’une sous-requête par l’un des six opérateurs decomparaison (=, <>, <, <=, >, >=) se révèle souvent utile.L’expression qui précède l’opérateur est évaluée pour obtenir une valeurunique.Ilenvademêmepourlasous-requêtequisuitl’opérateur.Ilexistecependantuneexceptionàcela:l’emploid’unopérateurdecomparaisonquantifié, qui est un opérateur de comparaison suivi d’un quantificateur(ANY,SOMEouALL).
Reprenons l’exemple de la base de données de Zetec. Cette base dedonnées possède une table CLIENTS chargée de mémoriser desinformationssurlessociétésquiachètentdesproduitsZetec.EllecomporteégalementunetableCONTACTScontenantdesinformationsconfidentiellessurlespersonnesquitravaillentdanslesentreprisesclientesdeZetec.LesTableaux12.4et12.5représententlastructuredecestables.
TABLEAU12.4LatableCLIENTS.
Type Colonne Contraintes
CLIENT_ID INTEGER PRIMARYKEY
SOCIETE CHAR(40)
ADRESSE_CLIENT CHAR(30)
VILLE_CLIENT CHAR(20)
ETAT_CLIENT CHAR(2)
CP_CLIENT CHAR(10)
TEL_CLIENT CHAR(12)
NIV_MOD INTEGER
TABLEAU12.5LatableCONTACTS.
Type Colonne Contraintes
CLIENT_ID INTEGER FOREIGNKEY
CONT_NOM CHAR(10)
CONT_PRENOM CHAR(16)
CONT_TELEPHONE CHAR(12)
CONT_INFO CHAR(50)
Supposez que vous recherchiez votre contact chez Olympic Sales, maisvousnevousrappelezplusduCLIENT_IDdecettesociété.Vouspouvezutiliserlarequêtesuivante:
SELECT*
FROMCONTACTS
WHERECLIENT_ID=
(SELECTCLIENT_ID
FROMCLIENTS
WHERESOCIETE=‘OlympicSales’);
Lerésultatobtenuestlesuivant:
CLIENT_IDCONT_PRENOMCONT_NOMCONT_TELEPHON
ECONT_INFO
-----------------------------------------
-------------
118JerryAttwater505-876-3456
Vajouerunrôle
majeurdansla
miseenoeuvredu
Websansfil.
Si vous utilisez une sous-requête dans une comparaison ‘=’, la listespécifiée dans la sous-requêteSELECTne doitmentionner qu’une seulecolonne (par exemple CLIENT_ID). Lorsqu’elle est exécutée, elle doitretourneruneseulelignedemanièreàproduireunevaleurunique.
Dans cet exemple, je suppose que la table CLIENTS ne contient qu’unelignedontlavaleurdelacolonneSOCIETEest‘OlympicSales’.Sil’instruction CREATE TABLE spécifie la contrainte UNIQUE pourSOCIETE, la sous-requête de l’exemple précédent retournerasystématiquementuneseulevaleur(ouaucune).Toutefois,cetypedesous-requêteest largementutiliséavecdescolonnesquine sontpas spécifiéescommeétantUNIQUE.
Vous ne pouvez alors que vous fier à votre connaissance de la base dedonnéespourprésumerquelacolonnen’estpasdupliquée.
SilacolonneSOCIETEdeplusieursclientsprend lavaleur‘OlympicSales’ (peut-être dans différentes régions), la sous-requête générera uneerreur.
Parailleurs,s’iln’yaaucunclientpourlasociétéindiquée,lasous-requêteest traitée comme si elle générait une valeur nulle et le résultat de lacomparaisondevient inconnu.Danscecas, laclauseWHEREne retourneaucuneligne(carellenedonnequeleslignespourlesquelleslaconditionest satisfaite, et élimine celles pour lesquelles la condition est fausse ouindéterminée). Cette situation peut survenir si une personne orthographiemallenomdelaSOCIETEentapantparexemple‘OlumpicSales’.
Mêmesil’opérateurd’égalité(=)estleplusutilisé,vouspouvezutiliserles cinq autres opérateurs de la mêmemanière. Pour chaque ligne de latable spécifiée dans l’instruction englobant la clause FROM, la valeurretournéeparlasous-requêteestcomparéeàcelledel’expressionfigurantdans la clause WHERE de l’instruction de niveau supérieur. Si lacomparaisonrenvoieunevaleurTrue,laligneestajoutéeàlatablerésultat.
Vouspouvezvousassurerquelasous-requêteretournerauneseulevaleurenutilisant une fonction d’agrégation. En effet, les fonctions d’agrégationretournenttoujoursuneseulevaleur(reportez-vousauChapitre3pourplusdedétails).Bienentendu,cettemanièredeprocédern’estutilequesivousvoulezlerésultatproduitparunetellefonction.
SupposonsmaintenantquevoussoyezcommercialchezZetec.Vousvoulezfaireunbonchiffred’affaires (pour réglerquelques factures en retard) etvousconcentrezvosventessurleproduitlepluscherdeZetec.Vouspouvezidentifierceproduitaveclarequêtesuivante:
SELECTMODELE,NOM_PROD,PRIX
FROMPRODUITS
WHEREPRIX=
(SELECTMAX(PRIX)
FROMPRODUITS);
Danscetexemplederequêteimbriquée,lasous-requêteetl’instructionquil’englobetravaillentsurlamêmetable.Lasous-requêteretourneuneuniquevaleur : le prix maximal trouvé dans la table PRODUITS. La requêteexterneretournetoutesleslignesdelatablePRODUITSoùFigureceprix.
L’exemple suivant est une sous-requête qui utilise un opérateur decomparaisonautreque=:
SELECTMODELE,NOM_PROD,PRIX
FROMPRODUITS
WHEREPRIX<
(SELECTAVG(PRIX)
FROMPRODUITS);
Lasous-requêteretourneunevaleur:leprixmoyendelatablePRODUITS.La requête externe retourne toutes les lignes de la tablePRODUITSdanslesquellesleprixestinférieurouégalàcettemoyenne.
DanslestandardinitialdeSQL,unecomparaisonnepouvaitavoirqu’uneseulesous-requête,etcelle-cidevaitseplaceràdroitedelacomparaison.SQL:1999permetd’utiliserdessous-requêtesàdroitecommeàgauchedel’opérateurdecomparaison.
LesquantificateursALL,SOMEetANYUne autre manière de s’assurer qu’une sous-requête retourne une seulevaleurconsisteà l’introduireavecunopérateurdecomparaisonquantifié.LequantificateuruniverselALLetlesquantificateursexistentielsSOMEetANYassociésàunopérateurdecomparaisontraitentlalisteretournéeparunesous-requêteetlaréduisentàuneseulevaleur.
Vous allez maintenant voir comment ces quantificateurs affectent unecomparaison en examinant la base de données des parties complètes debase-ballprésentéeauChapitre11.
Lecontenudesdeuxtablesestretournéparlesdeuxrequêtessuivantes:
SELECT*FROMNATIONALE
PRENOMNOMPARTIES_COMPLETES
-------------------------------
SalMaglie11
DonNewcombe9
SandyKoufax13
DonDrysdale12
BobTurley8
SELECT*FROMAMERICAINE
PRENOMNOMPARTIES_COMPLETES
-------------------------------
WhiteyFord12
DonLarson10
BobTurley8
AllieReynolds14
En théorie, les lanceursquiontparticipéauplusgrandnombredepartiescomplètes sont les membres de la Ligue américaine. Pour le vérifier, ilsuffitdeconstruireunerequêtequiretournetousleslanceursdecetteliguequiontparticipéàplusdepartiescomplètesque les lanceursde laLiguenationale.Cetterequêtepeutseformulercommesuit:
SELECT*
FROMAMERICAINE
WHEREPARTIES_COMPLETES>ALL
(SELECTPARTIES_COMPLETESFROM
NATIONALE);
Lerésultatestlesuivant:
PRENOMNOMPARTIES_COMPLETES
-------------------------------
AllieReynolds14
La sous-requête (SELECT PARTIES_COMPLETES FROM
NATIONALE)retournelesvaleursdelacolonnePARTIES_COMPLETESde tous les lanceurs de la Ligue nationale. Le quantificateur > ALL
indique qu’il ne faut retourner que les valeurs de PARTIES_COM-PLETES de la table AMERICAINE qui sont supérieures à toutes lesvaleurs renvoyéespar la sous-requête.La conditionpeutdonc se traduirepar « plus grande que la valeur la plus élevée retournée par la sous-requête».Dansnotre cas, lavaleur laplus élevée retournéepar la sous-requête est 13 (Sandy Koudax). La seule ligne dans la table
AMERICAINEdontlavaleurdelacolonnePARTIES_COMPLETESestsupérieure à13 est celle d’Allie Reynolds (il a participé à 14matchesentiers).
Etsivotrethéorieserévélaitfausse?Danscecas,larequêtesuivantevoussignaleraqu’aucundeslanceursdelaLigueaméricainen’aparticipéàplusdepartiescomplètesqu’unlanceurdelaLiguenationale(autrementditqu’iln’yaaucuneligneàretourner):
SELECT*
FROMAMERICAINE
WHEREPARTIES_COMPLETES>ALL
(SELECTPARTIES_COMPLETESFROMNATIONALE);
Requêtesimbriquéesservantdetestd’existenceUnerequêteretournedesdonnéesextraitesdetoutes les lignesdela tablequi satisfont aux conditions posées. Il arrive que de nombreuses lignessoientretournées.Parfois,ilyenasimplementuneseule.Maisilestaussipossible qu’aucune ligne ne satisfasse les conditions, et donc qu’aucunelignenesoitrenvoyée.VouspouvezutiliserlesprédicatsEXISTSetNOTEXISTSpourintroduireunesous-requête.Ilsvousindiquerontsilatableidentifiée dans la clauseFROM satisfait ou non les conditions énoncéesdanslaclauseWHERE.
Les sous-requêtes introduites par EXISTS ou NOT EXISTS sontfondamentalement différentes des autres sous-requêtes présentées dans cechapitre.Dans les exemplesprécédents,SQLexécute enpremier la sous-requête, puis utilise le résultat de cette opération à l’instruction quil’englobe.D’unautrecôté,EXISTSetNOTEXISTSsontdesexemplesdesous-requêtescorrélées.
Une sous-requête corrélée recherche tout d’abord la table et la lignespécifiée par l’instruction englobante, puis exécute la sous-requête sur laligne de la table qui correspond à la ligne courante de la table del’instructiondeplusniveau.
La sous-requête retourne soit une ouplusieurs lignes, soit aucune.Si ellerenvoieaumoinsuneligne,leprédicatEXISTSestvalidé,etl’instructionenglobante est exécutée. Dans les mêmes conditions, le prédicat NOTEXISTS ne sera pas validé et donc l’instruction ne sera pas exécutée.Lorsqu’une ligne de la table de l’instruction englobante a été traitée,l’opérationserépètepourlalignesuivante.Etainsidesuitejusqu’àcequetoutesleslignesdelatabledel’instructionenglobanteaientétépasséesenrevue.
EXISTSVousêtesunvendeurdeZetecCorporation,etvousdeveztéléphoneràtouslescontactsdesclientsdeZetecenCalifornie.Essayezlarequêtesuivante:
SELECT*
FROMCONTACTS
WHEREEXISTS
(SELECT*
FROMCLIENTS
WHERECLIENT_ETAT=‘CA’
ANDCONTACTS.CLIENT_ID=
CLIENTS.CLIENT_ID);
Remarquez laprésencedeCLIENT_IDqui référenceune colonnede larequête externe et la compare à une autre colonne (CLIENTS.CLIENT_ID) de la requête interne. Pour chaque ligne de la tableCONTACTStraitéeparlarequêteexterne,vousévaluezlarequêteinterneenutilisantsavaleurCLIENT_IDdans la clauseWHEREde la requêteinterne.
Voicicomment:
1. LacolonneCLIENT_IDrelielestablesCONTACTSet
CLIENTS.
2. SQLseplacesurlepremierenregistrementdelatable
CONTACT.IltrouvelalignedelatableCLIENTSquipossède
lemêmeCLIENT_ID,puistestelechampCLIENT_ETATde
cetteligne.
3. SiCLIENTS.CLIENT_ETAT=‘CA’,lalignecourantede
CONTACTSestajoutéeàlatablerésultat.
4. L’enregistrementsuivantesttraitédelamêmemanière,et
ainsidesuitejusqu’àcequelatableCONTACTSaitété
entièrementparcourue.
5. CommelarequêtespécifieSELECT*FROMCONTACTS,
tousleschampsdelatablesontaffichés,ycomprislenom
etlenumérodetéléphoned’uncontact.
NOTEXISTSDansl’exempleprécédent,levendeurdeZetecrecherchaitlesnomsetlesnumérosdetéléphonedescontactsdetouslesclientsrésidantenCalifornie.Imaginez qu’un second vendeur soit responsable de tous les États-Unis àl’exception de la Californie. Il peut récupérer la liste de ses contacts enutilisantNOTEXISTSdansunerequêtesemblableàlaprécédente:
SELECT*
FROMCONTACTS
WHERENOTEXISTS
(SELECT*
FROMCLIENTS
WHERECLIENT_ETAT=‘CA’
ANDCONTACTS.CLIENT_ID=
CLIENT.CLI-
ENT_ID);
ChaquelignedeCONTACTSpourlaquellelasous-requêteneretournerienestajoutéeàlatablerésultat.
Autressous-requêtescorréléesCommejel’aidéjàexpliquéplushaut,lessous-requêtesintroduitesparINou par un opérateur de comparaison n’ont pas besoin d’être des requêtescorrélées.Maisellespeuventl’être.
Sous-requêtescorréléesintroduitesparIN
Dans la section intitulée « Les sous-requêtes introduites par le mot cléIN»,j’aiexpliquécommentdessous-requêtesnoncorréléespeuventêtreutilisées avec le prédicatIN. Pour comprendre maintenant comment unesous-requêtecorréléeestcapabled’utiliser leprédicatIN,posons-nouslamême question qu’avec le prédicatEXISTS : «Quels sont les noms etnumérosdetéléphonedescontactsdeZetecenCalifornie?»Vouspouvezrépondreàcettequestionavecunesous-requêtecorréléeIN:
SELECT*
FROMCONTACTS
WHERE‘CA’IN
(SELECTCLIENT_ETAT
FROMCLIENTS
WHERECONTACTS.CLIENT_ID=
CLIENTS.CLIENT_ID);
L’instruction est évaluée pour chaque enregistrement de la tableCONTACTS. Si, pour cet enregistrement, les numéros CLIENT_ID dansCONTACTS et dans CLIENTS sont identiques, la valeur deCLIENTS.CLIENT_ETATest comparée à ‘CA’. Le résultat de la sous-requête estunelistequicontientauplusunélément.Sicetélémentest‘CA’,laclauseWHERE de l’instruction de niveau supérieur est validée et la ligne estajoutéedanslatablerésultat.
Sous-requêtes introduites par des opérateurs de
comparaison
Une sous-requête corrélée peut être également introduite par l’un des sixopérateursdecomparaison,commel’illustrel’exemplesuivant.
Zetec verse des primes à ses vendeurs en fonction du volume des ventesqu’ilsréalisentparmois.Pluscevolumeestimportant,pluslepourcentagede la prime est important. Ce pourcentage est conservé dans une tableappeléePRIMES:
MONTANT_MINMONTANT_MAXPCT_PRIME
-------------------------------
0.0024999.990.
25000.0049999.990.1
50000.0099999.990.2
100000.00249999.990.3
250000.00499999.990.4
500000.00749999.990.5
750000.00999999.990.6
Si les ventes mensuelles d’un vendeur sont comprises entre 100000et249999,99unités, lepourcentagedelaprimes’élèveà0,3%desventes.
LesventessontenregistréesdansunetableappeléeTRANSMASTER:
TRANSMASTER
-----------
ColonneTypeContraintes
-------------------------------
TRANS_IINTEGERPRIMARYKEY
CLIENT_IDINTEGERFOREIGNKEY
EMP_IDINTEGERFOREIGNKEY
TRANS_DATEDATE
MONTANT_NETNUMERIC
PORTNUMERIC
TAXESNUMERIC
TOTALFACTURENUMERIC
LaprimeestbaséesurlasommedeschampsMONTANT_NETdetouteslestransactionseffectuéesparunvendeurdurantlemois.Vouspouvezcalculer
laprimed’unvendeurenutilisantunesous-requêtecorréléequifaitappelauxopérateursdecomparaison:
SELECTPCT_PRIME
FROMPRIMES
WHEREMONTANT_MIN<=
(SELECTSUM(MONTANT_NET)
FROMTRANSMASTER
WHEREEMP_ID=133)
ANDMONTANT_MAX>=
(SELECTSUM(MONTANT_NET)
FROMTRANSMASTER
WHEREEMP_ID=133);
Cette requête est intéressante, car elle contient deux sous-requêtes reliéespar le connecteur logique AND. Les sous-requêtes utilisent l’opérateurd’agrégation SUM qui retourne une seule valeur : le montant total desventes réalisées par le vendeur numéro 133. Cette valeur est ensuitecomparée aux colonnesMONTANT_MIN etMONTANT_MAXde la tablePRIMESpourobtenirlaprimedececommercial.
SivousneconnaissezpaslavaleurEMP_ID,maislenomduvendeur,vousobtiendrezlemêmerésultatavecunerequêteunpeupluscomplexe:
SELECTPCT_PRIME
FROMPRIMES
WHEREMONTANT_MIN<=
(SELECTSUM(MONTANT_NET)
FROMTRANSMASTER
WHEREEMP_ID=133)
ANDMONTANT_MAX>=
(SELECTSUM(MONTANT_NET)
FROMTRANSMASTER
WHEREEMP_ID=133);
Cet exemple utilise des sous-requêtes imbriquées dans des sous-requêtes,qui sont à leur tour imbriquées dans une requête globale pour calculer laprimedel’employédénomméCoffin.Cettestructurenefonctionneraquesivousêtesabsolumentcertainque lasociétéemploieunetunseulvendeurappeléCoffin.Sil’entrepriseemploieplusieurspersonnesportantlemêmenom, vous pouvez ajouter des termes dans la clauseWHERE de la sous-requêtelaplusimbriquéejusqu’àcequevoussoyezsûrqu’uneseulelignedelatableEMPLOYESestsélectionnée.
Sous-requêtesdansuneclauseHAVING
ExactementcommedansuneclauseWHERE,vouspouvezutiliserunesous-requête corrélée dans une clause HAVING. Comme je l’explique auChapitre9, une clauseHAVING est généralement précédée d’une clauseGROUPBY.LaclauseHAVINGsecomportecommeunfiltrequiécrèmelesgroupescrééspar laclauseGROUPBY.Ceuxquine remplissentpaslesconditionsdelaclauseHAVINGnefigurentpasdanslerésultat.Dansce cas, la clauseHAVINGest employée pour chaque groupe créé par laclauseGROUPBY.
En l’absence de GROUP BY, la clause HAVING est exécutée pourl’ensemble des lignes retourné par la clauseWHERE, dont le résultat estalors assimilé à un seul groupe. Si ni WHERE ni GROUP BY ne sontprésentes,laclauseHAVINGestexécutéepourtoutelatable:
SELECTPCT_PRIME
FROMPRIMES
WHEREMONTANT_MIN<=
(SELECTSUM(MONTANT_NET)
FROMTRANSMASTER
WHEREEMP_ID=
(SELECTEMP_ID
FROMEMPLOYES
WHEREEMP_NOM=‘Coffin’))
ANDMONTANT_MAX>=
(SELECTSUM(MONTANT_NET)
FROMTRANSMASTER
WHEREEMP_ID=
(SELECTEMP_ID
FROMEMPLOYES
WHEREEMP_NOM=‘Coffin’));
Cette requête utilise deux alias pour la même table afin de pouvoirrécupérer lenumérod’identifiantde tous lesvendeursdont levolumedesventesestaumoinsdeuxfoiségalauvolumedesventesmoyennesdetouslesautresvendeurs.Cetterequêtefonctionnecommesuit:
1 LarequêteexterneregroupeleslignesdeTRANSMASTER
parEMP_ID.C’estletravaildesclausesSELECT,FROMet
GROUPBY.
2. LaclauseHAVINGfiltrecesgroupesetcalculepourchaque
groupeleMAXdelacolonneMONTANT_NETdeslignesde
cegroupe.
3. LarequêteinterneévaluedeuxfoisleMONTANT_NET
moyendetoutesleslignesdeTRANSMASTERdontle
EMP_IDestdifférentduEMP_IDdugroupecourantdela
requêteexterne.
Remarquezque,dansladernièreligne,vousdevez
référencerdeuxvaleursEMP_IDdifférentes,sibienqu’il
vousfaututiliserdesaliasdifférentsdeTRANSMASTERdans
lesclausesFROMdesrequêtesinternesetexternes.
4. Vouspouvezensuiteutilisercesaliasdanslacomparaison
deladernièrelignedelarequêtepourindiquerquevous
référencezàlafoisleEMP_IDdelalignecourantedela
sous-requêteinterne(TM2.EMP_ID)etleEMP_IDdu
groupecourantdelasous-requêteexterne(TM1.EMP_ID).
InstructionsUPDATE,DELETEetINSERTÀl’instardesinstructionsSELECT,lesinstructionsUPDATE,DELETEetINSERTpeuventégalementcomprendredesclausesWHERE.CesclausesWHEREsontaussisusceptiblesdecontenirdessous-requêtes,exactementcommelesclausesWHEREdesinstructionsSELECT.
Par exemple, Zetec vient tout juste de réaliser une vente importante avecOlympic Sales et veut rétroactivement concéder à Olympic une ristournede10%surtoussesachatsdumoisdernier.VouspouvezaccordercecréditavecuneinstructionUPDATE:
UPDATETRANSMASTER
SETMONTANT_NET=MONTANT_NET*0.9
WHERECLIENT_ID=
(SELECTCLIENT_ID
FROMCLIENTS
WHERECOMPAGNIE=‘OlympicSales’);
Vous pouvez également utiliser une sous-requête corrélée dans uneinstruction UPDATE. Supposez que la table CLIENTS contienne unecolonneMOIS_DERNIER_MAXetqueZetec accordeuncrédit de10%auxclientsdontlesachatsontdépasséMOIS_DERNIER_MAX:
UPDATETRANSMASTERTM
SETMONTANT_NET=MONTANT_NET*0.9
WHEREMONTANT_NET>
(SELECTMOIS_DERNIER_MAX
FROMCLIENTC
WHEREC.CLIENT_ID=TM.CLIENT_ID);
Remarquez que cette sous-requête est corrélée. La clauseWHEREde ladernièreligneréférenceàlafoisleCLIENT_IDdelaligneCLIENTSdelasous-requêteetleCLIENT_IDdelaligneTRANSMASTERcouranteàmettreàjour.
Unesous-requêtedansuneinstructionUPDATEpeutégalement référencerla tablequi est en coursdemise à jour.SupposezqueZetec accordeuneristournede10%auxclientsdontlesachatsontdépassé10000unités:
UPDATETRANSMASTERTM1
SETMONTANT_NET=MONTANT_NET*0.9
WHERE10000<
(SELECTSUM(MONTANT_NET)
FROMTRANSMASTERTM2
WHERETM1.CLIENT_ID=TM2.CLIENT_ID);
La sous-requête interne calcule le total (SUM) de la colonne MON-TANT_NET pour toutes les lignes de TRANSMASTER relatives à unmêmeclient.Concrètement,supposonsqueleclientvérifiantCLIENT_ID= 37 possède quatre lignes dans TRANSMASTER avec les valeurssuivantespourMONTANT_NET:3000,5000,2000et1000.Letotaldumontantnetpourcecodeclientestdoncde11000.
L’ordre dans lequel l’instructionUPDATE traite les lignes est défini parvotreimplémentationetdoncn’estpasenrèglegénéraleprévisible.L’ordrepeutvarierenfonctiondelamanièredontleslignessontagencéesdansledisque. Supposez que votre implémentation prenne les lignes deTRANSMASTER dans cet ordre : celle dont MONTANT_NET
vaut3000, puis celle dontMONTANT_NET vaut5000, et ainsi desuite.UnefoislestroispremièreslignesdeCLIENT_ID37traitées,leurvaleurMONTANT_NETdevient 2 700 (90% de 3 000), 4 500 (90%de5000)et1800(90%de2000).LorsquevousallezpasseràladernièrelignedeTRANSMASTERpourleCLIENT_ID37pourlaquelleMON-TANT_NET vaut 1 000, la SOMME retournée par la sous-requêtesembleravaloir10000,c’est-à-dire laSOMMEdesnouvellesvaleursdeMONTANT_NET des trois premières lignes duCLIENT_ID37 et de
l’ancienne valeur de MONTANT_NET de la dernière ligne duCLIENT_ID 37. Par conséquent, la dernière ligne du CLIENT_ID37n’estapparemmentpasmiseàjour,carlacomparaisonaveccettesomme n’est pas validée (10 000 n’est pas inférieur à SELECT (SUM(MONTANT_NET)). Mais ce n’est pas ainsi que fonctionne uneinstructionUPDATElorsqu’unesous-requêteréférenceunetablequiestencoursdemiseàjour.
Toutes les évaluations des sous-requêtes d’une instructionUPDATE fontréférence aux anciennes valeurs de la table à mettre à jour. Dans leprécédent UPDATE pour le CLIENT_ID 37, la sous-requêteretourne11000,quiestlasommeoriginale.
La sous-requête d’une clauseWHERE fonctionne exactement de lamêmemanièrequ’uneinstructionSELECTouune instructionUPDATE. Ilenvade même pour DELETE ou INSERT. Pour supprimer toutes lestransactionsrelativesàOlympic,utilisezcetteinstruction:
DELETETRANSMASTER
WHERECLIENT_ID=
(SELECTCLIENT_ID
FROMCLIENTS
WHERECOMPAGNIE=‘OlympicSales’);
Comme dans le cas d’UPDATE, les sous-requêtes DELETE peuventégalementêtrecorréléesetréférencéesdanslatableàsupprimer.Lesrèglesquivalentdanscecas sont identiquesà cellesqui s’appliquent aux sous-requêtesUPDATE.SupposonsquevousvouliezsupprimertoutesleslignesdeTRANSMASTERpourlesclientsdontleMONTANT_NETestsupérieurà10000unités:
UPDATETRANSMASTERTM1
WHERE10000<(SELECTSUM(NET_AMOUNT)
FROMTRANSMASTERTM2
WHERETM1.CLIENT_ID=TM2.CLIENT_ID);
Cette requête supprime toutes les lignes de TRANSMASTER pour leCLIENT_ID 37 ainsi que tous les autres clients dont les achatsdépassent10000unités.TouteslesréférencesàTRANSMASTERdanslasous-requête portent sur le contenu de cette table avant toute suppressionopéréepar l’instruction.Parconséquent, etmêmesivousêtesen traindesupprimerladernièrelignedeTRANSMASTERpourleCLIENT_ID37,la sous-requête sera évaluée sur la base de la table TRANSMASTERinitialeetretournera11000.
Lorsquevousmettezàjour,supprimezouinsérezdesenregistrementsdansune base de données, vous prenez le risque de rendre inconsistantes lesdonnéesdecettetableaveclesautrestablesdelabase.Cetteinconsistance,appelée anomalie de modification, est présentée au Chapitre 5. Si voussupprimez des enregistrements de TRANSMASTER et qu’une tableTRANSDETAIL dépend de TRANSMASTER, vous devez supprimer lesenregistrements correspondants dans TRANSDETAIL. Cette opération estappelée suppression en cascade, car l’effacement d’un enregistrementparentestrépercutésurlesenregistrementsenfantsquiluisontassociés.Sices suppressions n’avaient pas lieu, les enregistrements enfantsdeviendraientorphelins.
Si votre implémentation ne prend pas en charge les suppressions encascade,vousdevrezlesfairevous-même.Danscecas,supprimezd’abordles enregistrements de la table enfant, puis les enregistrementscorrespondantsdelatableparent.Vousn’aurezpasainsid’enregistrementsorphelinsdanslatableenfant.
RécupérerdesmodificationsaveclelangagedemanipulationdedonnéesDans les précédentes sections, vous avez appris comment une instructionUPDATE,DELETEou INSERT peut inclure une instruction imbriquéedansuneclauseWHERE.SQL:2011permetd’imbriquerunecommandedemanipulation de données (telles que UPDATE, INSERT, DELETE ouMERGE) dans une instruction SELECT. Cette fonctionnalité est appeléeinstructionDML.
Une autre façon demodifier des données consiste à considérer une tableavant toute opérationDELETE,INSERT, ouUPDATE. Nommez la table
avanttoutemodificationvieilletableetlatableaprèsmodificationnouvelletable. Pendant les modifications, des tables auxiliaires, appelées tablesdelta,sontcréées.UneopérationDELETEcréeunevieilletabledeltaquicontientleslignesàsupprimer.UneopérationINSERTcréeunenouvelletabledeltaquicontientleslignesàinsérer.UneopérationUPDATEcréeenmêmetempsunevieilleetunenouvelletabledelta,lavieillepourleslignesàsupprimeretlanouvellepourleslignesàremplacer.
Avec une DML vous pouvez récupérer les informations des tables delta.Supposez que vous supprimiez tous les produits PRODUIT_ID
entre1000et1399delaligneproduitetquevoussouhaitiezobtenirle compte-rendu exact de ce qui se passe quand tous ces produits sontsupprimés.Vouspourriezutiliserleslignesdecodeci-dessous:
SELECTOldtable.PRODUIT_ID
FROMOLDTABLE(DELETEFROMPRODUIT
WHEREPRODUIT_IDBETWEEN1000
AND1399)
ASOldtable;
Dans cet exemple, le mot clé OLD TABLE spécifie que le résultat deSELECTse trouvedans lavieille tabledelta.Le résultat est la listedesnumérosdeproduitssupprimés.
Vouspouvezaussirécupérerunelisted’unenouvelletabledeltaaveclemotcléNEWTABLEquiaffiche lesnumérosdePRO-DUIT_IDdes lignesinsérées par une opération INSERT ou mises à jour par une opérationUPDATE. Comme une opération UPDATE crée aussi bien une vieillequ’une nouvelle table, vous pouvez récupérer le contenu de l’une ou del’autreouencoredesdeuxavecuneDML.
L
Chapitre13Requêtesrécursives
DANSCECHAPITRE:
» Comprendrelarécursivité.
» Définirdesrequêtesrécursives.
» Savoirutiliserdesrequêtesrécursives.
’unedesprincipalescritiquesformuléesàl’encontredeSQL,jusqu’àsaversion SQL-92 incluse, était son incapacité à implémenter destraitementsrécursifs.Denombreuxproblèmessontdifficilesàrésoudre
sans recourir à la récursivité. Les extensions ajoutées àSQL:1999permettentd’effectuerdesrequêtesrécursives,accroissantainsila puissance du langage. Si l’implémentation de SQL que vous utilisezdispose de ces extensions, vous serez enmesure de résoudre nombre denouvellesclassesdeproblèmes.Cependant,commelarécursivitén’estpasune fonctionnalité obligatoire deSQL, de nombreuses implémentations nel’incluentpas.
Qu’est-cequelarécursivité?Lanotionderécursivitéestapparueilyabienlongtempsdansdeslangagesde programmation tels que Logo, LISP et C++. Dans ces langages, vouspouvez définir une fonction (ensemble constitué d’une ou plusieurscommandes) qui effectue une certaine opération. Le programme principalinvoque la fonctionenutilisantunecommandediteappelde fonction.Si,au cours de cette opération, la fonction s’appelle elle-même, vous êtesconfrontéàlaformelaplusélémentairederécursivité.
Unprogrammetrèssimpledontunedesfonctionsutiliselarécursivitépeutsuffireàexpliquerlesjoiesetlespeinesdecettetechnique.Leprogramme
suivant, écrit en C++, dessine une spirale à l’écran. Il comprend troisfonctions:
» Lafonctionligne(n)traceunelignedenunitésdelong.
» Lafonctiontourner_gauche(d)faittournerlaligneded
degrésdanslesensinversedesaiguillesd’unemontre.
» Lafonctionspirale(segment)quel’onpeutdéfinir
commesuit:
voidspirale(intsegment)
{
ligne(segment)
tourner_gauche(90)
spirale(segment+1)
};
Si nous appelons spirale (1) depuis le programme principal, lesactionssuivantessontentreprises:
spirale(1)traceunelignedeuneunitédelongverslehautdel’écran.
spirale(1)tournede90degrés.
spirale(1)appellespirale(2).
spirale(2)traceunelignededeuxunitésdelong
verslecôtégauchedel’écran.
spirale(2)tournede90degrés.
spirale(2)appellespirale(3).
…Etainsidesuite.
Pourfinir,leprogrammegénèrelaspiralereprésentéesurlaFigure13.1.
Houston,nousavonsunproblèmeCertes,notresituationn’estpasaussicritiquequecelled’Apollo13lorsquelesastronautesdurent rejoindre laTerrealorsque leurprincipale réserved’oxygène avait explosé dans l’espace. Mais un problème existe. Notrepetit programme échappe à notre contrôle. Il s’appelle sans cesse pourtracerdeslignesdeplusenpluslongues.Ilcontinueraainsijusqu’àcequ’ilait épuisé les ressources de l’ordinateur, ce qui générera un messaged’erreur.Danslepiredescas,l’ordinateurseplantera.
FIGURE13.1Résultatdel’appelspirale(1).
Leplantagen’estpasuneoptionCe scénario vous explique l’un des dangers de la récursivité. Unprogrammeécritpours’appelerinvoqueunenouvelleinstancedelui-même,quiàsontourfaitappelàuneautreinstancedelui-même,etainsidesuitejusqu’àl’infini.Cequin’estgénéralementpascequevoussouhaitez.
Pour pallier ce problème, les programmeurs intègrent une condition desortiedanslafonctionrécursive,c’est-à-direunelimiteàlaprofondeurdesappels récursifs. De cette manière, le programme peut effectuer l’actiondésiréeetseterminesansencombre.Nousallonsinclureunetelleconditiondesortiedansnotreprogrammededessindespiralepoursauvegarder lesressources de l’ordinateur et éviter de plonger l’élite des programmeursdansunedépressionnoire:
voidspirale2(intsegment)
{
if(segment<=10)
{
ligne(segment)
tourner_gauche(90)
spirale2(segment+1)
}
};
Lorsquevousfaitesappelàspirale2(1),lafonctions’exécute,puiss’appelle(récursivement)jusqu’àcequelavaleurdusegmentdépasse10.Lorsque segment =11, la structure if (segment<=10) retourneunevaleurFauxetlecodeàl’intérieurdesaccoladesn’estpasexécuté.Lecontrôle revient alors à l’appel précédent despirale2, puis revient àl’appel précédant cet appel précédent, et ainsi de suite jusqu’à ce que lecontrôlerevienneaupremierappel,cequimetfinauprogramme.
LaFigure13.2illustrecetteséquenced’appels.
FIGURE13.2Uneséried’appelsdescendantspuisascendantspourterminerle
programmedansdebonnesconditions.
Chaque fois qu’une fonction s’appelle elle-même, elle vous « enfonce »d’un niveau supplémentaire sous le programme principal qui constitue lepoint de départ de l’opération. Pour que le programme principal puissereprendre son cours normal, l’itération la plus « profonde » doit à unmoment donné remonter d’un niveau, c’est-à-dire redonner le contrôle à
l’itération qui l’a appelée.Cette itération fera demême, et ainsi de suitejusqu’àreveniraupremierappel,puisauprogrammeprincipal.
La récursivité est un outil puissant pour exécuter du code de manièrerépétitivelorsquevousneconnaissezpasàl’avancelenombredebouclesàparcourir. Il est idéal pour effectuer des recherches dans des structuresarborescentes,descircuitsélectroniquescomplexesouencoredesréseauxdedistributionpossédantdemultiplesniveaux.
Qu’est-cequ’unerequêterécursive?
Unerequêterécursiveestunerequêtequidépendfonctionnellementd’elle-même.Laformelaplussimpledecetypededépendancefonctionnelleestlasuivante:unerequêteQ1inclutunappelàelle-mêmedanslecorpsdeson expression. La situation devient plus complexe lorsque la requêteQ1dépendde la requêteQ2,quià son tourdépendde la requêteQ1.Onparlelàencorededépendancefonctionnelleetderécursivité,quelquesoitlenombrederequêtesintercaléesentrelepremieretlesecondappelàunemêmerequête.
Quandutiliserunerequêterécursive?
Lesrequêtesrécursivesvouspermettentdegagnerdutempsetd’éviterbiendes frustrations lorsque vous essayez de résoudre certains problèmes.Supposonsparexemplequevousayezgagnéunpassequivouspermetdevoyager gratuitement avec la compagnie aérienne Vannevar Airlines. Lapremière question que vous vous posez est : « Où puis-je allergratuitement ? » La table VOLS contient tous les vols proposés parVannevar.LeTableau13.1vousindiqueleursnuméros,lelieudedépartetlelieudedestination.
TABLEAU13.1LesvolsproposésparVannevarAirlines.
Nodevol Départ Arrivée
3141 Portland OrangeCounty
2173 Portland Charlotte
623 Portland DaytonaBeach
5440 OrangeCounty Montgomery
221 Charlotte Memphis
32 Memphis Champaign
981 Montgomery Memphis
LaFigure13.3illustrecesroutessurunecartedesÉtats-Unis.
Pourcommencer,vousallezcréerunetabledanslabasededonnéesVOLSdelamanièresuivante:
CREATETABLEVOLS(
NoVolINTEGERNOTNULL,
SourceCHARACTER(30),
FIGURE13.3LacartedesvolsdeVannevarAirlines.
DestinationCHARACTER(30)
);
Vous pourrez ensuite la remplir à l’aide des données listées dans leTableau13.1.
SupposonsalorsquevouspartiezdePortlandpour rendrevisiteàunamiquivit àMontgomery.Vousvousdemandez toutnaturellement :«Quellesvilles puis-je rejoindre depuis Portland par des vols deVannevar ? » et«Quelles villes puis-je rejoindre depuisMontgomery par des vols de lamême compagnie aérienne ? » Vous pouvez relier certaines villes sansescaleetd’autrespas.Pourobtenir la listede toutes lesdestinationsverslesquellesvouspouvezvousrendreàpartird’unevilledonnée(vialesvolsde Vannevar, évidemment), vous pouvez bien sûr procéder requête aprèsrequête,commeci-dessous.Saufquevous irezpeut-êtreplusviteavecunpapieretuncrayon...
LamanièrefortePourobtenirlerésultatescompté,etàsupposerquevousfassiezpreuvedepatience, vouspouvez effectuer une série de requêtes enprenantPortlandcommepointdedépart:
SELECTDestinationFROMVOLSWHERESource=
‘Portland’;
Cette première requête va retournerOrange County, Charlotte et DaytonaBeach. Votre deuxième requête peut utiliser le premier de ces résultatscommepointdedépart:
SELECTDestinationFROMVOLSWHERESource=
‘OrangeCoun-
ty’;
Cette deuxième requête renvoie Montgomery. Votre troisième requête varevenir au résultat de la première requête et utiliser le deuxième résultatcommepointdedépart:
SELECTDestinationFROMVOLSWHERESource=
‘Charlotte’;
La troisième requête donneMemphis. Votre quatrième requête revient aurésultatdelapremièrerequêteetutiliselerésultatrestantcommepointdedépart:
SELECTDestinationFROMVOLSWHERESource=
‘Daytona
Beach’;
Hélas ! Cette dernière requête procure un résultat nul, car Vannevar neproposepasdevolaudépartdeDaytonaBeach.Maisladeuxièmerequêtearetournéuneautreville(Montgomery)quipeutservirdepointdedépartdansvotrecinquièmerequête:
SELECTDestinationFROMVOLSWHERESource=
‘Montgomery’
;
La réponse est cette foisMemphis.Ce résultat est inutile, car vous savezdéjàqueMemphisest l’unedesvillesoùvouspouvezaller (danscecas,
via Charlotte). Par contre, vous pouvez l’utiliser comme point de départd’uneautrerequête:
SELECTDestinationFROMVOLSWHERESource=
‘Memphis’;
LarequêteretourneChampaign,quevouspouvezajouteràlalistedesvillesjoignables(mêmes’ilfautdeuxescalespourvousyrendre).Sivousavezenvie de découvrir unmaximumd’aéroports, vous pouvez tout aussi bienutiliserChampaigncommenouveaupointdedépart:
SELECTDestinationFROMVOLSWHERESource=
‘Champaign’;
Cetterequêteretourneunevaleurnulle,carVannevarneproposepasdevolaudépartdeChampaign.(Septrequêtesplustard!Tenezbon!)VannevarneproposeaucunvolaudépartdeDaytonaBeach,desortequesivousvousyrendez,vousnepourrezplus enpartir ! Il nevous resteraplusqu’àvousinscrireàl’universitédel’Illinoispoursuivrequelquescourssurlesbasesdedonnées.
En appliquant cette méthode, vous finirez (normalement) par réussir àrépondre à la question : « Quelles sont les villes que je peux rejoindredepuisPortland?»Maisl’enchaînementderequêtesdontlerésultatdépenddelaprécédenteserévèlecompliqué,pénibleet trèscoûteuxentempsdecalcul.
ÉconomiserdutempsavecunerequêterécursiveLasolutionbienplus simpleconsisteàécrireuneseule requête récursivequi effectuera toute la recherche en une seule opération. Voici la syntaxed’unetellerequête:
WITHRECURSIVE
JoignableDepuis(Source,Destination)
AS(SELECTSource,Destination
FROMVOLS
UNION
SELECTsr.Source,dt.Destination
FROMJoignableDepuissr,VOLSdt
WHEREsr.Destination=dt.Source
)
SELECT*FROMJoignableDepuis
WHERESource=‘Portland’;
Lors du premier passage récursif, VOLS contient sept lignes etJOIGNABLEDEPUISaucune.L’opérateurUNIONprendlesseptlignesdeVOLS et les copie dans JOIGNABLEDEPUIS. À ce stade,JOIGNABLEDEPUIScontientlesdonnéesindiquéesdansleTableau13.2.
Comme je l’ai déjà dit, la récursivité ne fait pas partie de SQL, et parconséquentcertainesimplémentationsnepeuventpasl’inclure.
TABLEAU13.2LecontenudeJOIGNABLEDEPUISaprèsunpassagerécursif.
Départ Arrivée
Portland OrangeCounty
Portland Charlotte
Portland DaytonaBeach
OrangeCounty Montgomery
Charlotte Memphis
Memphis Champaign
Montgomery Memphis
Audeuxièmepassage récursif, leschosescommencentàdevenirvraimentintéressantes.LaclauseWHERE(WHEREsr.Destination=dt.Source)signifiequevousrecherchezseulementleslignesdontlechampDestination de la table JOIGNABLEDEPUIS est égal au champ
Sourcede la tableVOLS. Pour chacune de ces lignes, vous prenez lechampSourcedelatableJOIGNABLEDEPUISetlechampDestinationdelatableVOLS,puisvousajoutezcesdeuxchampsàJOIGNABLEDEPUISpour formerunenouvelle ligne.LeTableau13.3vousprésente le résultatproduitparcetteitération.
Cesrésultatssontbienplusutiles.JOIGNABLEDEPUIScontientmaintenanttoutes les villes Destination que vous pouvez rejoindre depuis n’importequellevilleSource,avecousansescale.Lepassagerécursifsuivantpermetde traiter tous lesvoyagesàdeuxescalesetainsidesuite jusqu’àcequetouteslesvillesdedestinationaientétéatteintes.
Unefoislarechercherécursiveterminée,latroisièmeetdernièreinstructionSELECT (qui se trouve hors de l’appel récursif) extrait deJOIGNABLEDEPUISlesvillesquevouspouvezrejoindredepuisPortlandpar un volVannevar.Dans cet exemple, les six autres villes peuvent êtrejointesdepuisPortland(éventuellementenquelquesbondsaériens).
TABLEAU13.3LecontenudeJOIGNABLEDEPUISaprèsdeuxpassagesrécursifs.
Départ Arrivée
Portland OrangeCounty
Portland Charlotte
Portland DaytonaBeach
OrangeCounty Montgomery
Charlotte Memphis
Memphis Champaign
Montgomery Memphis
Portland Montgomery
Portland Memphis
OrangeCounty Memphis
Charlotte Champaign
Certes,lecodedelarequêterécursiveneparaîtpasplussimplequeceluidesseptrequêtesqu’ilremplace.Maisilprésentedeuxavantages:
» Unefoissonexécutionlancée,ileffectuetoutela
recherchesansinterventionexterne.
» Ilpeutfaireletravailtrèsvite.
SupposezquevoustraitiezavecunecompagnieaérienneréellequidessertbienplusdevillesqueVannevar:plusilyauradedestinations,plusvousaurezavantageàutiliserlaméthoderécursive.
En quoi cette requête est-elle récursive ? Nous avons définiJOIGNABLEDEPUISenfaisantréférenceàelle-même.LapartierécursivedeladéfinitionsetrouvedansladeuxièmeinstructionSELECT,cellequiest juste après l’appel à UNION. JOIGNABLEDEPUIS est une tabletemporaire qui se remplit progressivement de données tandis que sesuccèdentlespassagesrécursifs.
La recherche se poursuit jusqu’à ce que toutes les destinations possiblesaientétéajoutéesàJOIGNABLEDEPUIS.Lesdoublonssonttouséliminés,car l’opérateurUNIONn’intègrepas les lignes redondantesdans la tablerésultat. Une fois la recherche récursive achevée, JOIGNABLEDEPUIScontienttouteslesdestinationsquevouspouvezrejoindredepuisn’importequellevillededépart.LatroisièmeetdernièreinstructionSELECTfournitenfinlalistedesvillesaccessiblesdepuisPortland.Bonvoyage!
Àquoid’autrepeutmeservirunerequêterécursive?
Toutproblèmequevouspouvez représenter sous la formed’une structurearborescente peut éventuellement être résolu à l’aide d’une requêterécursive.Uneapplicationindustrielledesplusclassiquesestleprocessusdeconversiond’unematièrepremièreenproduit fini.Supposezquevotreentreprisefabriqueunnouveaumodèledevoitureàmoteurhybrideessence
etélectrique.Un telvéhiculeestcomposédenombreusesparties (moteur,batterie, etc.) qui sont à leur tour composées de nombreuses pièces pluspetites (électrodes, etc.), qui sont à leur tour composées de nombreuxélémentsencorepluspetits.
Ilestrelativementdifficiledegérercorrectementcespartiesdepartiesdansune base de données relationnelle qui ne sait pas utiliser la récursivité.Celle-ci vous permet de partir du véhicule complet et de vous frayer unchemin jusqu’au plus minuscule des composants. En faisant appel à lastructureWITHRECURSIVE,vouspourrezretrouverenpeudetempslesspécifications de la vis platinée qui maintient l’électrode négative de labatterieauxiliaire.
Larécursivitéestégalementunprocédénaturelpourrésoudreunproblèmedetype«Etsi?».Dansl’exempledeVannevarAirlines,etsiladirectiondécide de ne plus desservir Charlotte depuis Portland, en quoi celaaffectera-t-illalistedesvillesquevouspouvezrejoindredepuisPortland?Unerequêterécursivevousfournirarapidementlaréponse.
IVContrôlerlesopérations
DANSCETTEPARTIE:
Contrôlerl’accès.
Protégerlesdonnéesdelacorruption.
Appliquerdeslangagesprocéduraux.
T
Chapitre14Protégerunebasededonnées
DANSCECHAPITRE:
» Contrôlerl’accèsauxtablesd’unebasededonnées.
» Spécifierquiaaccèsàquoi.
» Accorderdesprivilègesd’accès.
» Retirerdesprivilègesd’accès.
» Empêcherlesaccèsnonautorisés.
» Transmettrelepouvoird’accorderdesprivilèges.
out administrateur système qui se respecte doit connaître les diversaspects du fonctionnement d’une base de données. C’est pourquoi j’aitraité dans les chapitres précédents des parties de SQL qui servent à
créeretmanipulerdesbasesdedonnées,puis(auChapitre3)présenté lesfonctionsdeSQLquipermettentdeprotégerlesbasesdedonnéesdediverssinistres.Dans ce chapitre, je vais examinerplus endétail les dommagessusceptiblesd’êtreengendrésparunemauvaiseutilisation.
Le responsable en charge d’une base de données peut désigner lespersonnes qui y ont accès, mais aussi spécifier le niveau de leursautorisations en leur accordant ou en leur retirant le droit d’accéder àcertaines parties du système.L’administrateur système amême le pouvoirde transmettre (oude retirer)unepartiede sespouvoirs endéléguant (ourefusant)àd’autreslapossibilitéd’accorder(ounon)certainsprivilègesàdes utilisateurs. Pour peu que vous sachiez les utiliser correctement, lesoutilsdeSQLliésàlasécuritéserévèlentparticulièrementefficacespourprotégerdesdonnéesimportantes.Parcontre,s’ilssontmalemployés,cesmêmes outils peuvent empêcher des utilisateurs légitimes de faire leurtravail.
Les bases de données contiennent souvent des informations destinées àresterconfidentielles,oudumoinsaccessiblesuniquementàdesutilisateursautorisés.C’estpourquoiSQLproposetouteunepalettedeniveauxd’accès.Celapeutallerdetoutàrien,avecdifférentsdegrésintermédiaires.Commeil a le pouvoir de contrôler avec précision les opérations auxquelles ontaccès les utilisateurs, l’administrateur de la base de données peut leuraccorderl’accèsàtouteslesdonnéesdontilsontbesoinpourtravailler,toutenleurinterdisantdevoiroudemanipulercertainespartiesdelabasededonnées.
LelangagedecontrôlededonnéesdeSQL(DCL)
Les instructions SQL que vous utilisez pour créer des bases de donnéesforment le langage de définition de données (DDL, Data DefinitionLanguage).Unefoislabasededonnéescréée,vouspouvezutiliserunautreensemble d’instructions SQL – connu sous le nom de langage demanipulation de données (DML, Data Manipulation Language) – pourajouter,supprimeroumodifierdesdonnées.SQLcomprendégalementunesérie d’instructions qui n’appartiennent à aucune de ces deux catégories.Lesprogrammeurss’yréfèrentquelquefoisenlesdésignantcollectivementsous le nom de langage de contrôle de données (DCL, Data ControlLanguage).LesinstructionsDCLserventprincipalementàprotégerlabasededonnéescontrelesaccèsnonautorisés,qu’ilstrouventleuroriginedansuneinteractionfâcheuseentreplusieursutilisateursdelabaseouunepannematérielle.Danscechapitre,jevaisvousexpliquercommentvousprotégerdecesaccèsnonautorisés.
Lesniveauxd’accèsdel’utilisateurSQLpermetdecontrôlerl’accèsàneuffonctionsdegestiondelabase:
» Création,visualisation,modification,suppression:Ces
fonctionscorrespondentauxopérationsINSERT,SELECT,
UPDATEetDELETEdontj’aiparléauChapitre6.
» Référencement:L’utilisationdumotcléREFERENCES
(dontj’aiparléauxChapitres3et5)consisteàappliquer
descontraintesd’intégritéréférentielleàunetablequi
dépendd’uneautretabledelabase.
» Utilisation:LemotcléUSAGEserapporteauxdomaines,
auxjeuxdecaractères,auxinterclassementsetaux
traductions(cestermessontdéfinisauChapitre5).
» Définitiondenouveauxtypesdedonnées:Vousgérez
lesnomsdetypesdedonnéesdéfinisparl’utilisateurviale
motcléUNDER.
» Répondreàunévénement:L’utilisationdumotclé
TRIGGERprovoquel’exécutiond’uneinstruction(oud’un
blocd’instructions)SQLchaquefoisqu’unévénement
prédéterminésurvient.
» Exécution:LemotcléEXECUTEprovoquel’exécution
d’unmoduledeprogramme.
L’administrateurdelabasededonnéesL’autoritésuprêmed’unebasededonnéesutiliséeparplusieurspersonnesestl’administrateurdelabasededonnées(DBA,DataBaseAdministrator).Le DBA possède tous les droits et privilèges pour accéder à toutes lesfonctionnalités de la base. Être DBA peut vous procurer un véritablesentiment de puissance, mais vous investit également d’une lourderesponsabilité. Étant donné l’étendue de votre pouvoir, vous pouvezfacilement semer le désordre dans votre base et détruire des milliersd’heures de travail. Un DBA doit toujours réfléchir clairement etsoigneusementauxconséquencesdesesactes.
LeDBAatouslesdroitssurlabasededonnées.Ilcontrôledeplustouslesdroits des autres utilisateurs. De cette manière, des personnes hautementdignesdeconfiancepeuventavoiraccèsàdesfonctions,etpeut-êtreàdestables,interditesàlamajoritédesautresutilisateurs.
Lameilleure façondedevenirDBAestd’installervous-mêmeunsystèmedegestiondebasesdedonnées.Cetteprocédurevousdonnerauncompte,ou login, et un mot de passe. Ce compte vous identifie comme étant unutilisateurdisposantdeprivilègesspéciaux.LesystèmedésignequelquefoiscetutilisateurparDBA,quelquefoisparadministrateursystème,voireparsuperutilisateur (désolé, lecostumedesuper-hérosn’estpas fournipar lamaison).Dans tous lescas,votrepremière tâche,une foisquevous serezconnecté,serademodifiervotremotdepassepardéfautpourleremplacerparquelquechosedeplussecret.
Si vous ne changez pas le mot de passe par défaut, n’importe quellepersonnequiliraitlemanuelseraitenmesured’usurperl’identitéduDBA.Jevousconseilledecommuniquervotrenouveaumotdepasseuniquementàun petit nombre de personnes totalement dignes de confiance.Après tout,unemétéoritepourraitvousdésintégrerdemainmatin,oubienvouspourriezgagnerauLotoetprendrelepremieravionpourtrèsloinausoleil,oubienencore être dans l’impossibilité de venir au bureau pour une quelconqueraison. Tout cela ne doit pas empêcher vos collègues de travailler. Uneautre personne peut devenir à son tour administrateur système dumomentqu’elle connaît le login et lemot de passe duDBApour se connecter ausystème.
Si vous disposez des privilèges du DBA, je vous conseille de ne vousconnecter sous cette identité que si vous devez effectuer une tâche quirequiertceniveaudeprivilèges.Unefoiscetravailaccompli,déconnectez-vous. Puis reconnectez-vous en utilisant le login et lemot de passe d’uncompteutilisépouraccomplirtouteslesautresopérationsderoutine.Cetteméthodepourravouséviterdecommettredeserreurssusceptiblesd’avoirdefâcheusesconséquencespourlesautresutilisateurs.
LespropriétairesdesobjetsdelabasededonnéesUneautreclassed’utilisateursprivilégiés,avecleDBA,estlepropriétaired’objetsdelabasededonnées.Parexemple,lestablesetlesvuessontdes
objetsdelabase.Toututilisateurquicréedetelsobjetspeutendéfinirlepropriétaire. Le propriétaire d’une table bénéficie de tous les privilègesassociésàcelle-ci,ycompris ledroitd’autoriserd’autresutilisateursàyaccéder.Du fait que les vues s’appuient sur des tables sous-jacentes, unepersonneautrequelepropriétaired’unetablealapossibilitédecréerunevue basée sur cette dernière.Mais le propriétaire de cette vue ne pourrajamaisexercersurlatablesous-jacentequelesdroitsquiluisontaccordés.Rappelez-vous donc qu’un utilisateur ne peut jamais contourner laprotection instaurée par le propriétaire d’une table par l’intermédiaired’unesimplevue.
LepublicDanslaterminologieréseau,le«public»désignetouslesutilisateursquine sont pas spécialement privilégiés (autrement dit, ni les DBA ni lespropriétairesd’objets)etàquiaucunutilisateurprivilégién’aaccordédedroit particulier. Si un utilisateur privilégié accorde certains droits aupublic, toute personne pouvant accéder au système est investie de cesmêmesdroits.
Dans la plupart des installations, il existe une hiérarchie des utilisateursbaséesur lesprivilègesqui leursontaccordés.AusommettrôneleDBA.Le public forme la base de la pyramide. La Figure 14.1 illustre cettehiérarchie.
Accorderdesprivilègesauxutilisateurs
Parlavertudesaposition,leDBAbénéficiedetouslesprivilègessurtousles objets de la base de données. Après tout, le propriétaire d’un objetpossèdetouslesprivilègesportantsurcetobjet,etlabasededonnéesestelle-même un objet. Par défaut, toute autre personne ne dispose d’aucunprivilège sur aucun objet, à moins que quelqu’un qui possède déjà cesprivilèges(ainsiqueledroitdelestransmettre)nelesluiaitexplicitementtransmis.Vouspouvez accorderdesprivilèges àunutilisateur enutilisantl’instructionGRANT.Sasyntaxeseprésentedelamanièresuivante:
FIGURE14.1Hiérarchiedesutilisateursenfonctiondesprivilègesd’accès.
GRANTliste_privilèges
ONobjet
TOliste_utilisateurs
[WITHHIERARCHYOPTION]
[WITHGRANTOPTION]
[GRANTEDBYauteur];
Danscetteinstruction,liste_privilègesestdéfiniainsi:
privilège[,privilège]...
ou:
ALLPRIVILEGES
Asontour,privilègesedéfinitcommesuit:
SELECT
|DELETE
|INSERT[(nom_colonne[,nom_colonne]...)]
|UPDATE[(nom_colonne[,nom_colonne]...)]
|REFERENCES[(nom_colonne[,nom_colonne]...)]
|USAGE
|UNDER
|TRIGGER
|EXECUTE
Dansl’instructionoriginale,objetreprésente:
[TABLE]nom_table
|DOMAINnom_domaine
|CHARACTERSETnom_jeu_de_caractères
|COLLATIONnom_interclassement
|TRANSLATIONnom_traduction
|TYPEnom_type_utilisateur
|SEQUENCEnom_générateur_séquence
|désignateur_routine_spécifique
Enfin,liste_utilisateursseprésenteainsi:
login[,login]...
|PUBLIC
L’auteurestsoitCURRENT_USER,soitCURRENT_ROLE.
Dans la syntaxe précédente, les vues sont considérées comme étant destables.LesprivilègesSELECT,DELETE,INSERT,UPDATE,TRIGGERetREFERENCESne concernent que les tables et les vues. Le privilègeUSAGE s’applique aux domaines, aux jeux de caractères, aux séquencesd’interclassement et aux traductions. Le privilège UNDER regardeuniquement les types. Quant à EXECUTE, il s’applique en principe auxmodulesdeprogrammes.Lessectionssuivantesprésententdiversexemplesd’utilisationdel’instructionGRANT.
Rôles
Unnom d’utilisateur est un type d’identificateur d’autorisation, mais cen’est pas le seul. Il identifie une personne (ou un programme) qui estautoriséeàeffectueruneouplusieursactionssurlabasededonnées.Dansune grande entreprise, accorder des privilèges particuliers à chaqueemployépeutviteserévélerfastidieuxetcoûteuxentemps.SQLrésoutceproblèmeenintroduisantlanotionderôle.
Unrôle, identifiéparunnomderôle,secomposed’unensembledezérosou plusieurs privilèges pouvant être accordés à un ensemble d’individusayantbesoindumêmeniveaud’accèsà labasededonnées.Parexemple,touteslespersonnesquiontlerôleGARDE_SECURITEdoiventposséderlesmêmes privilèges. Ces privilèges seront vraisemblablement différentsdeceuxaccordésauxpersonnesquiontlerôledeVENDEUR_COMPTOIR.
Les rôles ne font pas partie du noyau de la spécification de SQL. C’estpourquoicertaines implémentationsne lesproposentpas.Reportez-vousàladocumentationdevotreSGBDavantdetenterdelesutiliser.
Vouspouvezcréerdesrôlesenutilisantlasyntaxesuivante:
CREATEROLEVENDEURS;
Unefoislerôlecréé,vouspouvezaccorderdesprivilègesàdesutilisateursenfaisantappelàl’instructionGRANT:
GRANTVENDEURSTOCharles;
L’attributiondeprivilègesàunrôles’effectueexactementcommeaveclesutilisateursindividuels.Àunedifférenceprès:lerôleneseplaintpasetiln’accusepasleDBAdetouslesmaux.
InsérerdesdonnéesPouraccorderàunrôleleprivilèged’ajouterdesdonnéesdansunetable,suivezcetexemple:
GRANTINSERT
ONCLIENTS
TOVENDEURS;
Ce privilège permet à un vendeur d’ajouter de nouveaux clients dans latableCLIENTS.
ConsulterdesdonnéesPourpermettreàunutilisateurdeconsulterlesdonnéesd’unetable,servez-vousdel’exemplesuivant:
GRANTSELECT
ONPRODUITS
TOPUBLIC;
Ce privilège permet à quiconque ayant accès au système (PUBLIC) deconsulterlecontenudelatablePRODUITS.
Enréalité,accordercetypedeprivilègeestpotentiellementdangereux.Lescolonnes de la table PRODUITS peuvent contenir des informationsconfidentielles telles que PRIX_DE_GROS. Pour donner accès auxprincipales informations tout en interdisant la consultation des donnéessensibles, définissez une vue sur la table en éliminant les colonnesconfidentielles.Accordez ensuite leprivilègeSELECTsur la vue et nonsurlatable.L’exemplesuivantillustrelasyntaxeàemployer:
CREATEVIEWMARCHANDISESAS
SELECTMODELE,NOMPROD,DESCPROD,PRIX
FROMPRODUITS;
GRANTSELECT
ONMARCHANDISES
TOPUBLIC;
EnutilisantlavueMARCHANDISES,lepublicnepeutpasvoirlacolonnePRIX_DES_PRODUITSdelatablePRODUIToutouteautrecolonnequin’est pas mentionnée dans CREATE VIEW. Seules les colonnesexplicitementdéfiniesdanslavuesontaccessiblesaupublic.
Modifierlesdonnéesd’unetable
Danstouteorganisationactive,lesdonnéesstockéesdansunetableévoluentau fil du temps.Vous devez accorder à certaines personnes le droit et lepouvoird’effectuerdesmodifications,toutenempêchantd’autrespersonnesde le faire. Pour accorder des privilèges de modification, suivez cetexemple:
GRANTUPDATE(PRIMESVNT)
ONPRIMES
TORESPONSABLE_COMMERCIAL;
Leresponsablecommercialpeutajusterlepourcentagedesprimesverséesaux vendeurs (la colonne PRIMESVNT) en fonction des conditions dumarché. Toutefois, il ne peut pas modifier les valeurs des colonnesMONTANTMINetMONTANTMAXquicorrespondentauniveaudesprimes.Pour autoriser lamodification de toutes les colonnes, vous devez soit enlister tous les noms, soit n’en spécifier aucun, comme dans l’exemplesuivant:
GRANTUPDATE
ONBONUS
TODIRECTEUR_COMMERCIAL;
Supprimerleslignesobsolètesd’unetableDesclientsprennentleurretraite,changentd’activitéouchoisissentunautrefournisseur. Des employés démissionnent, partent à la retraite, sontlicenciés ou meurent. Des produits deviennent obsolètes. Bref, desinformations dont vous conservez la trace peuvent perdre un jour leurintérêt. Quelqu’un doit donc supprimer les enregistrements devenusobsolètes.Bienentendu,déléguercedroitdemandeuneréflexionpoussée.Là encore, l’instructionGRANTvous permet d’accorder un privilège desuppressionàuneoudestiercespersonnesdelamanièresuivante:
GRANTDELETE
ONEMPLOYES
TORESPONSABLE_DRH;
Ledirecteurdesressourceshumainespeutsupprimerdesenregistrementsdela table EMPLOYES, tout comme le DBA et le propriétaire de la tableEMPLOYES(quiestprobablementaussi leDBA).Aucuneautrepersonnene peut effacer des enregistrements (à moins qu’une autre instructionGRANTneluiaccordecepouvoir).
RéférencerdestablesliéesSi une table contient une clé étrangère qui correspond à la clé primaired’uneautre table, lesdonnéescontenuesdans la seconde tabledeviennentaccessibles aux utilisateurs de la première. Cette situation créepotentiellement une dangereuse « porte de derrière » par laquelle desutilisateurs non autorisés pourraient passer pour extraire des informationsconfidentielles. Dans ce cas, en effet, un utilisateur n’a pas besoin deposséderdesdroitsd’accèsàune tablepourdécouvrirquelquechosesurson contenu. Il lui suffit bien souvent d’avoir des droits d’accès sur unetable qui référence cette cible pour pouvoir également accéder à cettedernière.
Par exemple, supposez que la table LICENCIES contienne les noms desemployésquivontêtre licenciés lemoisprochain.Seuls les responsablesautorisés ont un accès SELECT à la table. Mais voilà qu’un employédécouvre que la clé primaire de la table est EMPID. Il crée alors unenouvelletableESPIONquiutiliseEMPIDcommecléétrangère,cequiluipermetdejeteruncoupd’œilsurLICENCIES.J’expliquecommentcréerune clé étrangère avec une clause REFERENCES au Chapitre 5. Cetteméthode mérite d’être placée en tête de la liste des techniques que toutadministrateursystèmesedoitdeconnaître.Voyonsceladeplusprès:
CREATETABLEESPION
(EMPIDINTEGERREFERENCESLICENCIES);
L’employé n’a plus qu’à insérer dans la table ESPION des lignes quicorrespondent aux identifiants de tous les employés. Toute insertion quiéchoue signifie que l’employé n’est pas licencié. Inversement, toute lignequelatableaccepted’ajoutersignifiequelapersonneadusouciàsefairepoursonavenirimmédiat.
Tout n’est pas perdu. SQL permet de prévenir ce type d’intrusion enrequérantd’unutilisateurprivilégiéqu’ilaccordeexplicitementledroitderéférencementauxautresutilisateurs.Parexemple:
GRANTREFERENCES(EMPID)
ONLICENCIEES
TORESPONSABLE_DRH;
Utiliserlesdomaines,lesjeuxdecaractères,lesséquencesd’interclassementetlestraductionsLesdomaines,lesjeuxdecaractères,lesséquencesd’interclassementetlestraductions posent également des problèmes de sécurité. C’est plusparticulièrementlecasdesdomaines.Vousdevezabsolumentéviterqu’ilsnesoientutiliséspoursapervosmesuresdesécurité.
Vous pouvez définir un domaine qui regroupe un ensemble de colonnes.Vousvoulezque toutescescolonnespartagent lemême typeet lesmêmescontraintes.LescolonnesquevousénumérezdansuneinstructionCREATEDOMAINhéritentdestypesetcontraintesdudomaine.Sivouslevoulez,ilrestepossibledesurchargercescaractéristiquespourcertainescolonnesenparticulier. Pour autant, les domaines restent une solution élégante pourattribuerlesmêmescaractéristiquesàtoutunensembledecolonnesenuneseuledéclaration.
Recourir aux domaines se révèle pratique si vous utilisez une série detablescontenantdescolonnesdontlescaractéristiquessontidentiques.Parexemple, la base de données de votre société peut comprendre plusieurstables, chacune possédant une colonne PRIX qui doit être de typeDECIMAL(10,2)et ne contenir quedesvaleurspositives inférieuresà10000.Avantdecréervostables,vouspourriezdéfinirundomainequispécifielescaractéristiquesdecettecolonnedelamanièresuivante:
CREATEDOMAINDOMAINE_TYPE_PRIXDECIMAL(10,2)
CHECK(VALUE>=0ANDVALUE<=10000);
Vous identifiez peut-être vos produits en les dénommantCodeProduitdanstoutesvostables.CecodeesttoujoursdutypeCHAR(5),lepremiercaractèreétantunelettrechoisiedanslalisteX,C,H,etledernierl’undesdeux chiffres 9 ou 0. Vous pouvez créer un domaine pour ces colonnescommesuit:
CREATEDOMAINDOMAINE_CODE_PRODUITCHAR(5)
CHECK(SUBSTR(VALUE,1,1)IN(‘X’,‘C’,‘H’)
ANDSUBSTR(VALUE,5,1)IN(‘9’,‘0’));
Lesdomainesétantenplace,vouspouvezmaintenantcréervostablesdelamanièresuivante:
CREATETABLEPRODUITS
(CODE_PRODUITDOMAINE_CODE_PRODUIT,
NOM_PRODUITCHAR(30),
PRIXDOMAINE_TYPE_PRIX);
Au lieu de fournir explicitement le type de données pour CODE_PRODUIT et PRIX dans la définition de la table, vous spécifiez leurdomaine,cequi leurattribue le typeadéquatet lescontraintesexplicitéesdansl’instructionCREATEDOMAIN.Lorsquevousutilisezdesdomaines,vous devez les prendre en compte dans la gestion de la sécurité.Que sepasse-t-ilsiunepersonneveututiliserundomainequevousavezcréé?Est-cequecelapeutposerdesproblèmes?Quesepasse-t-il siunepersonnecrée une table dont une colonne a pour domaine DOMAINE_TYPE_PRIX?Cettepersonnepourratesterprogressivementdesvaleursdeplusenplusimportantessurlacolonnejusqu’àcequ’uneentréesoitrejetée.Cefaisant,elleseracapablededéterminer la limitesupérieuredu typePRIXtellequevousl’avezspécifiéedanslaclauseCHECKdevotre instructionCREATEDOMAIN.Sicette informationauncaractèreconfidentiel,vousdevez interdire aux autres l’accès à DOMAINE_TYPE_PRIX. Pourprotégervostablesdetellessituations,SQLpermetdelimiterl’utilisationdes domaines aux seules personnes explicitement autorisées par leurpropriétaire.Seulscespropriétaires(etleDBA)peuventaccorderunetelle
permission.Si,aprèsanalyse,vousdécidezquecetagrémentnemettrapasenpérilvotresécurité,ilvoussuffirad’utiliseruneinstructioncommecelledel’exemplesuivant:
GRANTUSAGEONDOMAINE_TYPE_PRIXTO
RESPONSABLE_COMMER-
CIAL;
La suppression d’un domaine par DROP peut engendrer différentsproblèmes de sécurité. Si des tables contiennent des colonnes quiappartiennentaudomainequevous souhaitez supprimer,vousdevrez sansdoute détruire au préalable ces tables, sans quoi vous ne pourrez passupprimer le domaine. Chaque implémentation gère la suppression d’undomaine d’une manière particulière. SQL Server la traite d’une certainefaçon,Oracle d’une autre, et ainsi de suite.Dans tous les cas, il est plusprudent de restreindre les possibilités de suppression des domaines, toutcommecelledesjeuxdecaractères,desséquencesd’interclassementetdestraductions.
Provoquerl’exécutiond’instructionsSQLIl arriveparfoisqu’une instructionSQLdéclenche l’exécutiond’uneautreinstruction,voired’unblocentierd’instructions.
Cefacteurdéclenchantpeutêtreactivépartroistypesdephénomènes:unévénement,uninstantspécifiqueouunecertaineaction.
» Unévénementpeutdéclencher(trigger)unecertaine
instructionouuncertaingrouped’instructions.
» Uninstantdonnépeutdéterminerlemomentoùune
certaineactionestdéclenchée(soitjusteavant,soitjuste
aprèsl’événement).
» Uneactioncorrespondsimplementàl’exécutiond’uneou
plusieursinstructionsSQL.
Parexemple,vouspouvezutiliserunfacteurdéclenchantpourexécuterunecommandequivérifielavaliditéd’unenouvellevaleuravantd’autoriserunUPDATE.Silanouvellevaleurn’estpasvalide,lamiseàjourn’aurapaslieu.
UnutilisateurouunrôledoitposséderleprivilègeTRIGGERpouravoirledroitdedéclencheruneaction.Parexemple:
CREATETRIGGERSupprClientBEFOREDELETE
ONCLIENTSFOREACHROW
WHENDeptt=‘75
INSERTINTOLOGCLIENTVALUES(‘Clientparisien
suppri-
mé’);
Chaquefoisqu’unclienthabitantParisestsurlepointd’êtresupprimédelatableCLIENTS,uneentréedans la tableLOGCLIENTestajoutéeafindemémoriserceteffacement.
Accorderdesprivilègesentreniveaux
AuChapitre 2, je décris les types structurés comme une forme de typesdéfinis par l’utilisateur (UDT). L’essentiel de l’architecture des typesstructurésdécouled’idéesvenantdelaprogrammationorientéeobjet.L’unedecesidéesestlahiérarchie,oùuntypepeutavoirdessous-types, typesdontcertainsdesattributsdériventdeceuxdutypedonteux-mêmesdérivent(leur supertype). En plus d’hériter de ces attributs, ils peuvent aussidisposer d’attributs qui leur sont propres. Une hiérarchie de cette naturepeutcomprendredemultiplesniveaux,letypesetrouvanttoutenbasétantdésignécommeuntypefeuille,paranalogieàunearborescence.
Unetabletypéeestunetabledanslaquellechaqueligneestuneinstancedutypestructuréassocié.Unetelletablecomprendunecolonneparattributdesontypestructuréassocié.Lenometletypededonnéesdelacolonnesontidentiquesàceuxdel’attribut.
Par exemple, supposons que vous soyez l’auteur de peintures que vouscommercialisez dans des galeries. En plus de vos originaux, vouscommercialisez aussi des tirages limités numérotés et signés, des tiragesnonnumérotés,etdesposters.Vouspouvezcréeruntypestructurépourvosœuvresdelamanièresuivante:
CREATETYPESoeuvres(
artisteCHARACTERVARYING(30),
titreCHARACTERVARYING(50),
descriptionCHARACTERVARYING(256),
supportCHARACTERVARYING(20),
dateCreationDATE)
NOTFINAL
C’estencoreunefonctionnalitéquetouslesproduitsdeSGBDneproposentpas.Toutefois,PostgreSQLdisposedelacommandeCREATETYPE, toutcommeOracle11getSQLServer2012.
Entantqu’artistesouhaitantconserverlatracedevosœuvres,vousvoulezfaireladistinctionentrelesoriginauxetlesreproductions.Vouspourriezdeplus souhaiter distinguer les différents types de reproductions. LaFigure 14.2 vous présente un exemple d’utilisation d’une hiérarchie pourfacilitercesdistinctions.LetypeŒuvredisposedesous-types,quipeuventàleurtouravoirdessous-types.
Ilexisteunecorrespondanceunpourunentre les typesdans lahiérarchiedes types et les tables dans la hiérarchie de la table typée. Les tablesstandard,dont il estquestionauxChapitres4et5, nepeuvent pas figurerdansunehiérarchiesemblableàcelleévoquéeicipourlestablestypées.
FIGURE14-2Lahiérarchiedesœuvres.
Aulieud’utiliserunecléprimaire,une table typéedisposed’unecolonned’auto-référence qui garantit l’unicité d’un enregistrement, non seulementdanslasupertablequioccupelesommetdelahiérarchie,maisdanstoutesses sous-tables. La colonne d’auto-référence est spécifiée par une clauseREF IS dans la commande CREATE de la supertable. Lorsque cesystème d’auto-référencement estmis en place, l’unicité est assurée danstoutelahiérarchie.
Donnerlepouvoird’accorderdesprivilèges
LeDBApeutaccorderdesprivilègesàn’importequi.Lepropriétaired’unobjetpeutaccorderdesprivilèges surcetobjetàn’importequi.Mais lesutilisateursbénéficiantdecesprivilègesnepeuventpaslesrétrocéderàunetiercepersonne.
Seules les personnes désignées par le DBA ou le propriétaire peuventbénéficierdecesprivilèges.Histoiredemaîtriserlasituation...
Dustrictpointdevuedelasécurité,restreindreladélégationdeprivilègesesttotalementjustifié.Maisdesutilisateursontsouventbesoindedéléguerleur autorité. Le travail ne peut pas s’arrêter parce qu’une personne estmalade,envacancesouestsortiepourdéjeuner.
Vousdevezaccorderàcertainsutilisateurs lepouvoirde transmettre leursprivilèges à d’autres personnes. Pour cela, utilisez l’instruction GRANTaveclaclauseWITHGRANTOPTION.Parexemple:
GRANTUPDATE(PRIMESVDT)
ONPRIMES
TORESPONSABLE_COMMERCIAL
WITHGRANTOPTION;
Le responsable commercial peut maintenant transmettre le privilègeUPDATEenutilisantl’instructionsuivante:
GRANTUPDATE(PRIMESVDT)
ONPRIMES
TOASSISTANT_RESPONSABLE_COMMERCIAL;
Une fois cette instruction exécutée, l’assistant du responsable commercialpeuteffectuerdesmodificationsdanslacolonnePRIMESVDTde la tablePRIMES,cequiluiétaitinterditauparavant.
Le fait de déléguer des droits représente toujours un compromis entresécurité et commodité. Le propriétaire de la table PRIMES octroie uncontrôle considérable enaccordant leprivilègeUPDATEà l’assistant duresponsablecommercialviaWITHGRANTOPTION.Cepropriétairefaitun pari sur le fait que son assistant prendra à cœur ses nouvellesresponsabilitésetqu’ilnecourrapaslui-mêmelerisquededélégueràsontourceprivilègeàn’importequi.
RetirerdesprivilègesSivousavezledroitd’accorderdesprivilèges,vousdevezégalementêtreen mesure de les retirer. Les postes occupés par les salariés de votreentreprise peuvent évoluer, et donc enmême temps leurs besoins d’accèsaux données. Il peut même arriver qu’un de vos employés quitte votresociété pour aller travailler chez un concurrent.Dans ce cas, vous devezpouvoirluiretirerimmédiatementtoutprivilèged’accès.
L’instructionREVOKEde SQL permet de supprimer des privilèges. Ellefonctionne comme l’instruction GRANT, à ceci près qu’elle a l’effetinverse.Sasyntaxeestlasuivante:
REVOKE[GRANTOPTIONFOR]liste_privilèges
ONobjet
FROMliste_utilisateurs[RESTRICT|CASCADE];
Vous pouvez employer cette structure pour annuler des privilègesspécifiques tout en laissant intacts les autres. L’instruction REVOKE sedistingue principalement de GRANT par la présence d’un des mots clésoptionnelsRESTRICTouCASCADE.
VousavezutiliséWITHGRANTOPTIONpouraccorderdesprivilègesàunutilisateur.Sivousvoulezéventuellementannulercesprivilèges,utilisezl’optionCASCADEdansl’instructionREVOKE.Voussupprimerezdumêmecoupencascadelesprivilègesquecetutilisateurapuaccorderàd’autrespersonnes.
D’un autre côté, l’option RESTRICT de l’instruction REVOKE nefonctionne que si le délégataire n’a pas à son tour transmis ces droitsspécifiques. En d’autres termes, vous retirez certains privilèges à telutilisateurdonné.Maissicelui-ci lesadéjàdiffusésàdroiteetàgauche,l’instructionREVOKEaccompagnéedel’optionRESTRICTnerévoquerapersonneetsecontenteraderetournerunmessaged’erreur.
Vous pouvez utiliser l’instruction REVOKE avec la clause GRANTOPTIONFORpourannulerledroitpourunepersonnedetransmettredesprivilèges(toutenlesconservantpourelle-même).
Si la clause GRANT OPTION FOR et le mot clé CASCADE sontprésents, vous révoquez tous les privilèges accordés à une personnedonnée, de même que tous les droits de cet individu à rétrocéder sesprivilèges.Danslemeilleurdescas,c’estenquelquesortecommesivousn’aviez jamais rien autorisé.Laprésence simultanéede la clauseGRANTOPTIONFORetdumotcléCASCADEpeutproduirel’unedessituationssuivantes:
» Silebénéficiairedel’instructionGRANTn’ajamaisdélégué
lesdroitsainsiacquisàd’autresutilisateurs,l’instruction
REVOKEestexécutée,etellesupprimeleoulesprivilèges
concernésencascade.
» Silebénéficiairedel’instructionGRANTadéjàdéléguéau
moinsl’undesprivilègesdontildispose,l’instruction
REVOKEn’estpasexécutéeetellerenvoieuncoded’erreur.
Le fait que vous puissiez accorder des privilèges avec WITH GRANTOPTION,puisquevouspuissiezlesrévoquersélectivement,rendlagestiondelasécuritépluscomplexequ’iln’yparaîtàpremièrevue.Parexemple,plusieurs personnes ayant des droits identiques pourraient accorder lemêmeprivilègeàunseulutilisateur.Sil’undeces«délégataires»révoquece privilège, l’utilisateur continuera à en bénéficier encore via les droitsqui lui ont été accordés par d’autres. Si un privilège est transmis d’unutilisateuràunautreavecWITHGRANTOPTION,cettesituationcréeunechaîne de dépendance dans laquelle les privilèges d’un utilisateurdépendentdeceuxd’unautreutilisateur.SivousêtesDBAoupropriétaired’unobjet,veillez toujours, aprèsavoirutiliséWITHGRANTOPTION,que le privilège ainsi délégué ne puisse pas réapparaître là où vous nel’attendez pas. Supprimer un privilège pour certains utilisateursindésirables, touten leconservantpourceuxquiyont légitimementdroit,représente une tâche particulièrement délicate. En règle générale,l’utilisation des clauses GRANT OPTION et CASCADE engendre denombreuses et délicates subtilités. Si vous utilisez ces clauses, lisezsoigneusement la documentation de votre produit et les spécifications dustandard SQL pour vous assurer que vous comprenez bien leurfonctionnement.
UtilisersimultanémentGRANTetREVOKEpourgagnerdutempsetdesefforts
Accorder de multiples privilèges sur des colonnes d’une table à denombreuxutilisateurspeutreprésenterdesmassesdelignesd’instructions.Considérez cet exemple : le directeur commercial souhaite que tous les
commerciaux puissent consulter la table CLIENTS. Mais seuls lesresponsablescommerciauxpeuventmettreàjour,supprimerouinsérerdeslignes.PersonnenedevraitmodifierlechampCLIENT_ID.Lesnomsdesresponsables commerciaux sont Tyson, Keith et David. Vous pouvez leuraccorder les privilèges adéquats avec des instructions GRANT de lamanièresuivante:
GRANTSELECT,INSERT,DELETE
ONCLIENTS
TOTYSON,KEITH,DAVID;
GRANTUPDATE
ONCLIENTS(SOCIETE,ADRESSE,VILLE,
ETAT,CODE_POSTAL,TELEPHONE)
TOTYSON,KEITH,DAVID;
GRANTSELECT
ONCLIENTS
TOJENNY,VALERIE,MELODY,NEIL,ROBERT,SAM,
BRANDON,MICHELLE_T,ALLISON,ANDREW,
SCOTT,MICHELLE_B,JAIME,LINLEIGH,MATT,AMANDA
;
Ainsi chacun bénéficie des droits SELECT sur la table CLIENTS. Lesresponsables commerciaux bénéficient en plus des droits INSERT etDELETEcompletssurcettetable.Ilspeuventenparticuliermodifiertouteslescolonnesàl’exceptiondeCLIENT_ID.
Lasolutionsuivantedonneplusrapidementlemêmerésultat:
GRANTSELECT
ONCLIENTS
TORESPVENTES;
GRANTINSERT,DELETE,UPDATE
ONCLIENTS
TOTYSON,KEITH,DAVID;
REVOKEUPDATE
ONCLIENTS(CUST_ID)
FROMTYSON,KEITH,DAVID;
Lenombred’instructionsestidentique,etleniveaudeprotectionégalement.Maisces instructionssontbienplussimplesàsaisir,carvousnenommezpas tous lesutilisateursdudépartementcommercialni toutes lescolonnesde la table. Le temps de saisie ainsi gagné est également un gain deproductivité,cequiestl’idéesous-jacenteprincipale.
V
Chapitre15Protectiondesdonnées
DANSCECHAPITRE:
» Préserverunebasededonnées.
» Comprendrelesproblèmesdusàdesopérationsconcurrentes.
» GérerlesproblèmesdeconcurrenceaveclesmécanismesdeSQL.
» ProtectionsurmesureavecSETTRANSACTION.
» Protégervosdonnéessansnuireàlaproductivité.
ousdevezconnaître la loideMurphy–engros, siquelquechosepeutaller de travers, elle ira de travers. Cette pseudo-loi est un sujet deplaisanterie,car,danslaplupartdescas,leschosessedéroulentcomme
nous l’avions prévu. Si un problème inattendu survient, vous serezprobablementenmesuredeledétecteretdelerésoudre.
Mais cequi est vrai pournousne l’est pas forcémentpourdes structurescomplexes (un mathématicien vous expliquerait que le risque croîtapproximativementcommelecarrédelacomplexité).Unebasededonnéesmulti-utilisateur est une structure complexe. De multiples problèmespeuvent seproduire lorsde son fonctionnement.Denombreusesméthodesontétédéveloppéespourminimiserl’impactdecesproblèmes,maisellesn’ont jamaispermisde les éliminer complètement (cequidoit réjouir lesprofessionnels de la maintenance des bases de données, car il semblevirtuellementimpossibled’automatiserleurtravail).Danscechapitre,nousallonsnouspencher sur lesprincipaux risquesquimenacentvosbasesdedonnées, et nous étudierons les outils que fournit SQL pour traiter lesproblèmessusceptiblesdeseposeràvous.
Menacessurl’intégritédesdonnées
Lecyberespace(ycomprisvotreréseau)estunbelendroitàvisiter,maiscen’estpas tous les jours fêtepour lesdonnéesquiy résident.Vosdonnéespeuventêtreendommagéesoucorrompuesdetoutessortesdemanières.AuChapitre 5, j’ai abordé les problèmes liés à une mauvaise saisie, auxerreursdemanipulationetauxdestructionsintentionnelles.DesinstructionsSQL mal formulées ou des applications mal conçues peuvent égalementendommager vos données. À ces menaces s’ajoutent l’instabilité de laplate-formeetleséventuellespannesdumatériel.Jevaistraiterdecesdeuxdernierspointsdanslessectionsquisuivent,ainsiquedesproblèmesliésauxaccèsconcurrents.
Instabilitédelaplate-formeL’instabilité de la plate-forme est une question qui ne devrait même pasexister.Malheureusement,ellesepose,etceavecd’autantplusd’acuitéquevotre système fonctionne avec des composants qui n’ont pas étésérieusement testés. Un problème d’instabilité peut survenir aprèsl’installation d’une nouvelle version du SGBD ou du systèmed’exploitation, ou encore après l’ajout d’un nouveau matériel. Vous êtesalors confronté à des situations totalement inattendues. Et cela se produitévidemment à un moment critique pour votre travail. Votre système seplante, vos données sont endommagées. Rien ne va plus. À part insultervotre ordinateur et ceux qui l’ont fabriqué, il ne vous reste guère d’autresolutionqued’espérerquevotredernièresauvegardesoitlabonne.
Nestockez jamaisdesdonnées importantes surunsystèmedans lequeluncomposantquelconquen’apasététesté.Résistezàlatentationdevousjetersurlatoutenouvelleversionbêta,pourtantsialléchante,devotreSGBDoudevotresystèmed’exploitation.Sivousavezl’impressionquevousdevezvousfairelamainsurunnouveloutil,faites-lesurunemachinetotalementisoléedevotreenvironnementdeproduction.
PannematérielleLeplusmodernedeséquipementsn’estpasàl’abrid’unepannequirisquede faire franchir leStyxàvosdonnées.Le risquen’est jamaisnul,mêmeavecunordinateurderniercriethautdegamme.Siunincidentmatérielseproduitalorsquevotrebasededonnéesestouverteetactive,vouspouvezd’évidenceperdredesdonnées,parfoismêmesansvousenrendrecompte.
Cetypedepannesurvienttoujoursunjouroul’autre.Etsicejour-làlaloideMurphys’applique,ceserapourvouslepiredesmoments.
L’unedessolutionspourprotégervosdonnéesdespannesmatériellesestlaredondance. Conservez une copie de tout. Pour une sécurité maximale,procurez-vousunecopie conformede la configurationmatérielledevotreenvironnement de production (si tant est que cet investissement soit à laportée de votre organisation). Faites des sauvegardes de votre base dedonnéesetdevosapplicationsquevouspourrezchargersur ledoubledevotreenvironnementdeproductionaussitôtqu’unepanneseproduit.Si lecoût d’une telle redondance vous paraît exorbitant, faites a minimarégulièrement une sauvegarde de votre base de données et de vosapplications,detellesortequevousn’ayezpasàressaisirunetropgrandequantitédedonnéesencasdepanne.
Une autre solution pour vous préserver des pannesmatérielles consiste àutiliser des transactions, dont il est question à la fin de ce chapitre.Unetransactionestuneunitéindivisibledetravail.Autrementdit,ellenepeutêtreexécutéequ’enentieroupasdutout.Cetteapprochedutoutourienpeutparaître drastique. Cela dit, les pires problèmes apparaissent lorsqu’uneséried’opérations sur labaseest interrompueencoursde traitement.Lestransactionsdiminuentdonc le risquedevoirvosdonnéescorrompuesouperdues,etcemêmeencasdedéfaillancedumatérielsurlequelrésidelabase.
AccèsconcurrentSupposez que vous utilisiez un logiciel et du matériel certifiés, que vosdonnéessoientbonnes,quevosapplicationssoientexemptesdeboguesetque tout votre équipement soit parfaitement fiable. Le rêve ? Pas encore.Des problèmes peuvent apparaître lorsque plusieurs personnes essaientd’accéder simultanément à la même table d’une base de données (c’estl’accèsconcurrent),etqueleursordinateurs tergiversentsurceluiquidoitpasserenpremier(c’est lacontention).Lessystèmesdebasesdedonnéesmulti-utilisateurs doivent être capables de gérer efficacement une tellesituation.
Problèmed’interactiondetransaction
Des problèmes de contention peuvent apparaître dans n’importe quelleapplication. Considérez le cas suivant : vous écrivez une applicationdestinée à passer des commandes qui fait intervenir quatre tables :COMMANDES, CLIENTS, LIGNE_OB-JET et INVENTAIRE. Lesconditionssuivantessontappliquées:
» LatableCOMMANDESaNUMERO_COMMANDEcomme
cléprimaireetNUMERO_CLIENTcommecléétrangèrequi
référencelatableCLIENTS.
» LatableLIGNES_COMMANDEaNUMERO_LIGNEcomme
cléprimaireetNUMERO_OBJETcommecléétrangèrequi
référencelatableINVENTAIRE.Ellecontientégalementune
colonneQUANTITE.
» LatableINVENTAIREaNUMERO_OBJETcommeclé
primaireetcontientégalementunchampappelé
QUANTITE_DISPO-NIBLE.
Ces trois tables possèdent d’autres colonnes qui n’interviennent pas danscet exemple.La stratégie devotre société consiste à traiter complètementchaquecommandeoupasdutout.Autrementdit,aucunecommandepartiellen’est autorisée (pas de panique, ce n’est qu’une situation hypothétique).Vous allez écrire une application TRAITER_COMMANDE qui traiterachaquecommandeenregistréedans la tableCOMMANDES.L’applicationva commencer par déterminer s’il est possible d’expédier tous les objetscommandés. Si c’est le cas, elle écrira la commande, puis décrémenteracomme il convient la colonne QUANTITE_DISPONIBLE de la tableINVENTAIRE.Cetteaction supprimeraaupassage lesentréesconcernéesdestablesCOMMANDESetLIGNES_COMMANDE.
L’application est conçue pour traiter les commandes de l’une des deuxmanièressuivantes lorsqueplusieursutilisateursaccèdent simultanémentàlabase:
» Lapremièreméthodeconsisteàtraiterlaligne
d’INVENTAIREquicorrespondàchaquelignedelatable
LIGNES_COMMANDE.SiQUANTITE_DISPONIBLEest
suffisant,l’applicationdécrémentecechamp.Silavaleurde
QUANTITE_DISPONIBLEn’estpasassezgrande,elle
annulelatransactionetrevientsurtouteslesopérations
quiontaffectélesautresobjetsLIGNES_COMMANDEde
cettecommande.
» Lasecondeméthodeconsisteàvérifierchaqueligne
d’INVENTAIREcorrespondantàuneligne
LIGNES_COMMANDEdelacommande.Sitoutesles
quantitéssontsuffisantes,l’applicationlestraiteenles
décrémentant.
En règle générale, la première méthode s’avère la plus efficace si letraitementdelacommanderéussit.Parcontre,lasecondeméthodeestplusefficaceencasd’échec.Silaplusgrandepartdescommandesesthonoréela plupart du temps, il est préférable d’employer la premièreméthode.Àl’inverse,siunemajoritédecommandesalafâcheusehabituded’échouer,il vaut mieux appliquer la seconde méthode. Supposons que cetteapplicationhypothétiquesoitencoursd’exploitationsurunsystèmemulti-utilisateur dépourvu d’un contrôle adéquat des accès concurrents. Vousentendezdéjàlesifflementdesballes?Voiciunéchantillondesproblèmesquipeuventalorssurvenir:
1. Unclientcontacteunvendeur(nousl’appellerons
utilisateur1).Ilveutcommander10sécateurs(objet1)
etcinqtondeuses(objet37).
2. L’utilisateur1emploielaméthode1pourtraiterla
commande.Ilcommenceparlesdixexemplairesde
l’objet1(lessécateurs).
Commeilsedoit,vousavezeffectivementdixsécateursen
stocketl’utilisateur1lesprendtous.
Lafonctiondetraitementdescommandesdécrémentela
quantitéenstockdel’objet1pourlapasseràzéro.Etc’est
iciqueleschosesdeviennentintéressantes.Unautreclient
contactevotreentreprisepourpasserune(toutepetite)
commande.Cettefois,c’estl’utilisateur2quiluirépond.
3. L’utilisateur2essaied’enregistrerlacommanded’un
seulexemplairedel’objet1.Ilconstatealorsqu’ilne
resteplusaucunsécateur.
Lacommandedel’utilisateur2estannulée,carellenepeut
pasêtrehonorée.
4. Pendantcetemps,l’utilisateur1continueàtraiterla
commandeens’occupantdescinqexemplairesde
l’objet37(lestondeuses).
Malheureusement,iln’yenaplusquequatreenstock.La
commandedel’utilisateur1estdoncannulée,puisqu’ellene
peutpasêtrehonoréeintégralement.
LatableINVENTAIREseretrouveàprésentdanssonétat
initial,caraucunutilisateurn’aputraitersacommande.Les
deuxcommandessontperdues,bienquecellede
l’utilisateur2auraitpuêtresatisfaite.Votresociétéestmal
partie...
La méthode 2 n’est pas plus efficace, mais pour une raison différente.L’utilisateur 1 pourrait vérifier la disponibilité de tous les objets qu’ilcommande et décider que ces objets sont disponibles. Puisl’utilisateur2 intervient et passe commandede l’undecesproduits avantque l’utilisateur 1 ait réalisé la décrémentation. La transaction del’utilisateur1échoue.
Sérialiserpouréviterlesproblèmesd’interaction
Aucunconflitneseproduitsilestransactionssontexécutéesensérieetnonconcurremment.Danslepremierexemple,silatransactionmalheureusedel’utilisateur1s’étaitterminéeavantquenedébutecelledel’utilisateur2,lafonctionROLLBACKaurait rendudisponible la tondeuse commandéeparl’utilisateur2.RappelonsqueROLLBACKestunemachineà remonter letempsquiannulelatotalitéd’unetransaction.
Si les transactions avaient été traitées en série dans le second exemple,l’utilisateur 2 n’aurait jamais pu modifier la quantité disponible d’unproduittantquelatransactiondel’utilisateur1n’auraitpasétéachevée.Latransaction de l’utilisateur 1 se serait alors déroulée correctement (en seconcluantsoitparuneréussite,soitparunéchec),etl’utilisateur2auraitpuvérifiersil’objetqu’ilsouhaitaitcommanderétaitréellementdisponible.
Si les transactions sont exécutées en série, l’une après l’autre, ellesn’interféreront jamais. L’exécution de transactions concurrentes estditesérialisée si le résultat obtenu est le même que celui que produiraitl’exécutionensériedecestransactions.
Sérialiser des transactions concurrentes n’est pas la panacée. Entre seprotégerdesinteractionsmalencontreusesetpréserverlesperformances,ilfaut trouver le justemilieu.Plusvous isolez les transactions lesunesdesautres, plus il faut de temps pour les exécuter.Contrôler demanière troptatillonne les accès concurrents peut nuire aux performances générales dusystème.Seprotégerest indispensable,maisunesurprotectionneferaquedégraderleschoses.
Réduirelerisquedecorruptiondesdonnées
Vous pouvez prendre des précautions à plusieurs niveaux pour éviter deperdredesdonnéeslorsd’uneinteractioninattendueoud’unepanne.IlestpossibledeconfigurervotreSGBDdetellesortequ’ilgèrecertainesdecesprécautions à votre place. Tel un ange gardien, il vous protégera dumalsans que vous n’en sachiez jamais rien. Vous ne verrez rien. D’ailleurs,vousnevoudrezsansdoutemêmepassavoirqueleSGBDestentraindevousaider.Votreadministrateurdebasededonnées(DBA)peutégalementétablir des précautions à sa discrétion. Et vous en serez éventuellementinforméounonseloncequ’ilauradécidé.Enfin,entantquedéveloppeur,
vousvousdevezde suivre lamêmedémarche lorsquevous écrivezvotrecode.
Vous vous éviterez un grand nombre de problèmes en prenant l’habituded’appliquer automatiquement ces quelques principes élémentaires (que cesoitdansvotrecodeoudansvosinteractionsaveclabasededonnées):
» UtilisezlestransactionsSQL.
» Trouvezlejustemilieuentreperformancesetprotection.
» Sachezquandetcommentutiliserdestransactions,
verrouillerdesobjetsdelabasededonnéeseteffectuer
dessauvegardes.
Détaillonsmaintenantcesnotions.
UtiliserlestransactionsSQLLa transaction est l’un des principaux outils qu’offre SQL pourmaintenirl’intégritéd’unebasededonnées.Une transactionSQLenglobe toutes lesinstructions qui ont un effet sur la base. Elle se termine soit par uneinstructionCOMMIT,soitparuneinstructionROLLBACK.
» SiunetransactionsetermineparCOMMIT,leseffetsde
touteslesinstructionsdecettetransactionsontrépercutés
danslabasededonnéesenuneseuleséquencetrès
rapide.
» SiunetransactionsetermineparROLLBACK,leseffetsde
touteslesinstructionssontannulésetlabasededonnées
retrouvel’étatquiétaitlesienavantquenedébutecette
transaction.
Letermeapplicationdésigneicisoitl’exécutiond’unprogramme(qu’ilsoiten Cobol, C++ ou tout autre langage), soit une série d’actions effectuéesdepuisunterminallorsd’uneseulesession.
Uneapplicationpeutcomprendreplusieurs transactionsSQL.Lapremièretransaction commence avec cette application, et la dernière transaction setermine avec elle. Chaque COMMIT ou ROLLBACK effectué parl’applicationtermineunetransactionSQLetmarqueledébutdelasuivante.Par exemple, une application qui contient trois transactions SQL pourraitadopterlaformesuivante:
Débutdel’application
DiversesinstructionsSQL(SQLtransaction-1)
COMMITouROLLBACK
DiversesinstructionsSQL(SQLtransaction-2)
COMMITouROLLBACK
DiversesinstructionsSQL(SQLtransaction-3)
COMMITouROLLBACK
Findel’application
J’emploie le terme de « transaction SQL », car l’application peut faireappelàd’autressortesdefonctionnalitésdemêmetype(parexemplelorsd’unaccèsauréseau).Danslespagessuivantes,«transaction»sous-entenddonc«transactionSQL».
UnetransactionSQLnormaleaunmoded’accèsquiestsoitREAD_WRITE(lecture et écriture), soitREAD_ONLY (écriture seule). Elle a un niveaud’isolation qui est soit SERIALIZABLE, soitREPEATABLEREAD, soitREAD COMMITTED, soit READ UNCOMMITTED (reportez-vous plusloin à la section « Niveaux d’isolation » pour plus de détails). Lescaractéristiques par défaut sont READ_WRITE et SERIALIZABLE. Sivous voulez utiliser d’autres réglages, vous devez les spécifier avec uneinstructionSETTRANSACTION.Parexemple:
SETTRANSACTIONREADONLY;
Ouencore:
SETTRANSACTIONREADONLYREPEATABLEREAD;
Oubien:
SETTRANSACTIONREADCOMMITTED;
UneapplicationpeutcontenirplusieursinstructionsSETTRANSACTION,maisvousnepouvezenutiliserqu’uneseulepartransaction,etildoits’agirde la première instruction exécutée dans le cadre de cette transaction. Ilvousfautdonclaplacersoitaudébutdel’application,soitaprèsCOMMITou ROLLBACK. Vous devez faire appel à une instruction SET
TRANSACTIONaudébutdetoutetransactionquinesecontenterapasdespropriétéspardéfaut,carchaquenouvelle transactionsuivantunCOMMITouunROLLBACKadopteautomatiquementcespropriétés.
Une instruction SET TRANSACTION peut également spécifier unDIAGNOSTICS SIZE qui fixe le nombre de conditions d’erreur surlesquellesl’implémentationdevraconserverdesinformations(instaurerunetelle limite est indispensable, car une implémentation peut détecter plusd’uneerreuraucoursd’unemêmeinstruction).LavaleurSQLpardéfautdecettelimitedépenddel’implémentation,maiselleestpratiquementtoujoursadéquate.
LatransactionpardéfautLes caractéristiques de la transaction SQL par défaut répondent en règlegénérale aux besoins de la plupart des utilisateurs. Mais vous pouvezspécifier d’autres propriétés via une instruction SET TRANSACTIONcommecelaaétéexpliquédanslasectionprécédente(ilseraparailleursquestiondeSETTRANSACTIONplusloindanscechapitre).
La transaction par défaut s’appuie par ailleurs sur deux suppositionsimplicites:
» Labasededonnéesvachangeraufildutemps.
» Ilesttoujourspréférabledetravaillerensécuritéquede
regrettersesactes.
C’est pourquoi elle applique le mode READ-WRITE qui vous permetd’exécuter des instructions destinées à modifier la base de données. Deplus,elleutiliseleniveaud’isolationSERIALIZABLE,quicorrespondau
niveau le plus élevé d’isolation (et donc le plus sûr). DIAGNOSTICSSIZE prend une valeur par défaut qui dépend de l’implémentation.Reportez-vous à la documentation SQL de votre système pour en savoirplus.
Niveauxd’isolationDansl’idéal, le travailaccompliparvotre transactionest totalement isolédutravailaccompliparlesautrestransactions,mêmesielless’exécutentdemanière concurrente.Mais, dans la réalité, il n’est pas toujours possibled’atteindreunniveaud’isolationparfait surunsystèmemulti-utilisateur, àmoinsdesacrifierlesperformances.Laquestionestdonc:«Jusqu’àquelpointsouhaitez-vous isoler les transactions lesunesdesautresetcombienêtes-vousprêtàpayerpourcelaentermesdeperformances?»
LecturesaleLeplusfaibledesniveauxd’isolationestappeléREADUNCOMMITTED.Il vous expose au problème de la lecture sale. Vous êtes en lecture salelorsqu’unutilisateurpeutconsulterlavaleurd’unedonnéemodifiéeparuneseconde personne avant que cette modification n’ait été validée par uneinstructionCOMMIT.
Le problème apparaît lorsque le second utilisateur annule sa transaction.Lesopérationseffectuéesensuiteparlepremierutilisateursontalorsbaséessurunevaleur incorrecte.L’exempleclassiqueest celuid’uneapplicationd’inventaire : un utilisateur décrémente l’inventaire, un second lit lanouvellevaleur.Lepremierutilisateurannulesatransaction(cequirendàl’inventairesavaleurinitiale).Lesecondutilisateur,quicroitquelestockest presque épuisé, passe une commande pour le renouveler, alors qu’enréalitévousn’avezbesoinderien.
N’utilisez jamais le niveau d’isolation READ UNCOMMITTED, à moinsquevotrebutnesoitpasderécupérerdesrésultatsprécis.
VouspouvezvousplacerauniveauREADUNCOMMITTEDsivousvoulezgénérerdesstatistiquestellesque:
» Ledélaimaximalentrelepassagededeuxcommandes.
» Lamoyenned’âgedescommerciauxquin’atteignentpas
leurobjectifdevente.
» Lamoyenned’âgedesnouveauxemployés.
Dansdetelscas,desinformationsapproximativessuffisent.Leprixàpayeren termes de performances pour un renforcement du contrôle des accèsconcurrents n’en vaut sans doute pas la chandelle (d’ailleurs, celle-ci nevous aiderait pas à faire fonctionner votre réseau en cas de panne decourant...).
LalecturenonrépétableLe niveau d’isolation suivant estREADCOMMITTED. Une modificationeffectuée dans le cadre d’une autre transaction n’est pas vue par la vôtretantque lesecondutilisateurn’apasfinalisésonopérationenémettantunCOMMIT. Ce niveau donne de meilleurs résultats que READ
UNCOMMITTED,mais il pose le problème de la lecture qui ne peut êtrerépétée. Cela ressemble à un titre de comédie, mais c’est un problèmesérieux.
Reprenons l’exemple de l’inventaire. L’utilisateur 1 interroge la base dedonnées pour connaître le nombre d’exemplaires disponibles d’un certainproduit.Laréponseest10.Quasimentenmêmetemps,l’utilisateur2entamepuisvalideunetransactionquipasseunecommandede10exemplairesdece produit. Le stock est évidemment décrémenté, et passe donc à zéro.L’utilisateur1,quiavuque10exemplairesétaientdisponibles,essaied’encommandercinq.Maisiln’enrestemêmepluscinq.Lapremièrelecturedel’utilisateur1nepeutêtre répétée.Laquantitéachangésansqu’ilensoitaverti. Toutes les décisions qu’il va prendre en fonction de sa premièrelecturesontinvalides.
LalecturefantômeLeniveaud’isolationREPEATABLEREADéviteleproblèmeprécédent.Toutefois,ceniveaud’isolationestàsontourhantéparleproblèmedelalecture fantôme, qui survient lorsque la donnée que cet utilisateur est entraindelireestmodifiéeenréponseàuneautretransactionetqu’iln’enestpasimmédiatementinforméàl’écran.
Supposonsparexemplequenotreutilisateur1passeunecommandedontlescritèresderecherche(clausesWHEREetHAVING)désignentunensembledelignes. Immédiatementaprès,unutilisateur2modifiedesdonnéesdansquelques-unes de ces lignes. Ces dernières répondaient peut-être auxcritèresderecherchedel’utilisateur1avantl’interventiondel’utilisateur2,maiscen’estpluslecasàprésent.Ilestmêmepossiblequedeslignesquinevérifiaientpaslescritèresderechercheinitiauxyrépondentmaintenant.L’utilisateur1,dontlatransactionesttoujoursactive,n’estpasinformédesmodifications apportées par l’utilisateur 2. L’application se comportecomme si de rien n’était. Si l’utilisateur 1 effectue à nouveau la mêmerecherche,ilvarécupérerdeslignesdifférentesdecellesquiluiavaientétéretournéeslapremièrefois.Lafiabilitédesrésultatsaétévampiriséeparlalecturefantôme.
Obtenirunelectureefficace(etsansdoutepluslente)Leniveau d’isolationSERIALIZABLEévite tous les problèmes décritsci-dessus.Àceniveau,lestransactionsconcurrentespeuventêtreexécutéessans aucune interférence entre elles, et les résultats produits seront lesmêmes que si elles avaient été exécutées en série (l’une après l’autre) etnonenparallèle.Mêmeàceniveaud’isolation,desproblèmesdelogicielet de matériel peuvent certes toujours provoquer l’échec de vostransactions. Mais vous n’aurez plus à vous inquiéter de la validité desrésultatssivousêtescertainquevotresystèmefonctionnecorrectement.
Naturellement, cette fiabilité supérieure a un prix en termes deperformances.LeTableau15.1faitlepointsurlesniveauxd’isolationetlesproblèmesqu’ilsrésolvent.
TABLEAU15.1Niveauxd’isolationetproblèmesrésolus.
Niveau
d’isolation
Problèmes
résolus
Lecturequine
peutêtre
répétée
Lecturequine
peutêtre
répétée
Lecture
fantôme
READ
UNCOMMITTED
Aucun Non Non Non
READ
COMMITTED
Lecture
sale
Oui Non Non
REPEATABLE
READ
Lecture
sale
Oui Oui Non
SERIALIZABLE Lecture
sale
Non Oui Oui
InstructionimplicitededébutdetransactionCertainesimplémentationsdeSQLexigentquevousleursignaliezledébutd’une transactionà l’aided’une instructionexplicite tellequeBEGIN ouBEGINTRAN.MaislestandardSQLnel’imposepas.Sivousn’êtespasdanslecadred’unetransactionactive,maisexécutezuneinstructionquienrequiert une, SQL initiera pour vous une transaction par défaut.CREATETABLE,SELECT etUPDATE sont autant d’exemples d’instructions quiontbesoinpourfonctionnerducontexted’unetransaction.Lancezunedecesinstructions,etSQLouvriraunetransactionàvotreplace.
SETTRANSACTIONÀ l’occasion, vous pouvez avoir à utiliser une transaction dont lescaractéristiquessontdifférentesdesvaleurspardéfaut.Ilestalorspossibledespécifiercespropriétésàl’aidedel’instructionSETTRANSACTION(etce,avantd’exécuterlapremièreinstructionquirequiertunetransaction).SET TRANSACTION vous permet de spécifier un mode, un niveaud’isolationetunelimitedediagnostic.
Pourchangerparexemplecestroiscaractéristiquesàlafois,vouspouvezutiliserl’instructionsuivante:
SETTRANSACTION
READONLY,
ISOLATIONLEVELREADUNCOMMITTED,
DIAGNOSTICSSIZE4;
Avec ce paramétrage, vous ne pourrez pas exécuter d’instructions quimodifient la base de données (READ ONLY) et vous aurez spécifié leniveau d’isolation le plus bas (READ UNCOMMITTED). La limite dediagnostic est de 4. Vous utilisez donc le minimum des ressources dusystème.
Regardezmaintenantcetteinstruction:
SETTRANSACTION
READWRITE,
ISOLATIONLEVELSERIALIZABLE,
DIAGNOSTICSSIZE8;
Cescaractéristiquesvouspermettentdemodifierlabasededonnées.Ellesvous donnent le plus haut niveau d’isolation et repoussent la limite dediagnostic à la valeur 8. Ces paramètres mobilisent davantage lesressources du système. En fonction de la nature de l’implémentation quevousutilisez,cespropriétéspeuvent(ounon)êtreidentiquesàcellesdelatransaction par défaut. Naturellement, toutes les combinaisons possiblessontapriorienvisageables.
Utilisez toujours le niveau d’isolation qui correspond à vos besoins.L’utilisationconstanteduniveauSERIALIZABLEpeutsemblerunebonnesolution, mais ce n’est pas vrai pour tous les systèmes. Selon votreimplémentation et ce que vous faites, elle peut en effet pénaliser lesperformancesdefaçonsignificative.Sivousnecomptezpasmodifiervotrebasededonnéesaucoursdelatransaction,passezaumodeREADONLY.Respectezlarègled’or:nejamaiss’approprierlesressourcesdusystèmedontvousn’avezpasbesoin.
COMMITLestandardSQLnepossèdepasdemotcléexplicitepoursignalerledébutd’unetransaction.Parcontre,ilencontientdeuxquispécifientlafind’unetransaction:COMMITetROLLBACK.UtilisezCOMMITsivoussouhaitezvalider les modifications apportées à la base de données. Vous disposez
aussi dumot clé optionnelWORK (COMMITWORK). S’il se produit uneerreurdanslabase,ousilesystèmeplantelorsdel’exécutiondeCOMMIT,vous devrez certainement annuler la transaction, puis essayer de larecommencerànouveau.
ROLLBACKLorsqu’une transaction se termine, vous pouvez décider d’invalider lesmodificationsapportéesàlabaselorsdecettetransaction.Enfait,lebutestalors de restaurer la base dans l’état qui était le sien avant que latransaction ne débute. Pour cela, exécutez une instruction ROLLBACK.ROLLBACKestunmécanismerésistantauxerreurs.
Même si le système se plante lors de l’exécution de ROLLBACK, vouspourrezrelancercetteinstructionunefoislesystèmerétabli.Ellereprendrasontravailetrestaureralabasededonnéesdanssonétatprétransactionnel.
VerrouillerlesobjetsdelabasededonnéesLe niveau d’isolation spécifié par défaut (ou par une instruction SETTRANSACTION) détermine le degré de zèle dont doit faire preuve votreSGBD pour protéger votre travail des interactions avec celui des autresutilisateurs. La principale protection que vous offre le SGBD contre destransactions dangereuses est la possibilité de verrouiller les objets de labasededonnéesquevousutilisez.Voiciquelquesexemples:
UNEBASEACID
Ilarrivequecertainsconcepteursdisentqu’ilsveulentqueleursbases
dedonnéessoientACID.Celanesignifiepasdutoutqu’ilssouhaitent
les dissoudre dans un bouillon fumant. ACID est simplement un
acronymequisignifieAtomicité,Consistance,Isolation,Durabilité.Ces
quatre caractéristiques sont nécessairespourprotégerunebasede
donnéescontrelacorruption:
» Atomicité:Une transactiondevrait êtreatomiqueau sens
classique du terme, autrement dit être traitée comme une
unité indivisible. Soit elle est exécutée en totalité (COMMIT),
soit labaseestrestauréedanssonétatantérieur,commesi
latransactionn’avaitjamaisexisté(ROLLBACK).
» Consistance : Curieusement, la signification de la
consistance n’est pas particulièrement cohérente (ou
l’inverse).Ellevarieeneffetd’uneapplicationàuneautre.Si
vous transférezparexempledes fondsentredeux comptes
bancaires, le total de l’argent sur l’ensemble des deux
comptes ne devrait pas varier entre le début et la fin de la
transaction. Dans une autre situation, votre critère de
consistancepourraittrèsbienêtredifférent.
» Isolation : Dans l’idéal, toutes les transactions qui
s’exécutent simultanément sur une base de données
devraient être totalement isolées les unesdes autres. Cette
condition est remplie si ces transactions sont sérialisables.
Mais lorsqu’un système a à traiter un ensemble de
transactions avec un très haut débit, abaisser le niveau
d’isolationpeutêtreutilepouraméliorerlesperformances.
» Durabilité : Une fois votre transaction terminée (soit par
COMMIT,soitparROLLBACK),vousdevezavoirlacertitudeque
la base se trouve dans l’état voulu : avec des données
parfaitement enregistrées, non corrompues, fiables, à jour.
Même si votre système vous lâche brutalement après un
COMMIT(maisavantquelesrésultatsdelatransactionsoient
enregistrés sur le disque), un SGBD durable doit être en
mesuredegarantirquelabaseserabienrestauréedansl’état
quivientd’êtredécrit.
» Lalignedelatablesurlaquellevousêtesentrainde
travaillerestverrouillée.Lesautresutilisateursnepeuvent
pasaccéderàcetenregistrement.
» Unetableestverrouilléedanssatotalitésivouseffectuez
uneopérationsusceptibledel’affecterglobalement.
» L’accèsenlectureestautorisé,maispasl’écriture.Parfois,
c’estl’inverse.
Chaque implémentation dispose d’un système de verrouillage qui lui estpropre. Certaines sont plus sûres que d’autres. Mais la majorité dessystèmesrécentsvousprotègentdesproblèmeslesplusgravessusceptiblesdesurvenirlorsd’accèsconcurrents.
SauvegardervosdonnéesVotre DBA devrait effectuer régulièrement des sauvegardes. Il estindispensable de sauvegarder tous les éléments du système au bout d’uncertainlapsdetempsquiestfonctiondelafréquencedeleurutilisation.Sivous mettez à jour quotidiennement votre base de données, il faut lasauvegarder tous les jours. Vos applications, formulaires et rapportspeuvent aussi évoluer, mais moins souvent. Chaque fois qu’ils serontactualisés,votreDBAdevraensauvegarderlesnouvellesversions.
Conservezplusieursgénérationsdesauvegarde.Unproblèmesurvenudansla base de données peut n’être diagnostiqué que bien plus tard. Pourrestaurer la dernière bonne version, vous devrez revenir en arrière deplusieurssauvegardes.
Ilexisteplusieursméthodesdesauvegarde:
» UtiliserSQLpourcréerdestablesdesauvegardeety
copierlesdonnées.
» Utiliserunmécanismespécifiqueàl’implémentationqui
sauvegardetoutoupartieducontenudelabasede
données.Cettesolutionestenrèglegénéralebienplus
efficaceetplussimpleàmettreenœuvrequefaireappelà
SQL.
Votre installation peut comporter un mécanisme capable de toutsauvegarder,ycomprislesbasesdedonnées,lesdocuments,lesfeuillesdecalcul, lesutilitaires et les jeuxvidéo.Dansce cas, il nevous resteplusqu’à vérifier si les sauvegardes sont effectuées assez régulièrement pourvousprotéger.
Pointsdesauvegardeetsous-transactionsDans l’idéal, les transactions devraient être atomiques, aussi indivisiblesque les Grecs le pensaient des plus petits éléments de la matière.Cependant, les atomes ne sont pas vraiment indivisibles. On a découvertdepuis longtemps qu’ils sont constitués de parties plus petites, électrons,protons et neutrons, dont on sait aujourd’hui qu’elles ne sont même pasatomiquespuisqu’ellessontconstituéesdequarksetdegluons.
Depuis laversionSQL:1999, les transactionssur lesbasesdedonnéesnesont pas non plus réellement atomiques. Une transaction peut êtresubdivisée en plusieurs sous-transactions. Chaque sous-transaction setermine par une instruction SAVEPOINT, qui est utilisée conjointementavecl’instructionROLLBACK.Avantlacréationdespointsdesauvegarde(l’endroit du programme où l’instruction SAVEPOINT prend effet),l’instructionROLLBACKétaitutiliséeuniquementpourannulerl’intégralitédelatransaction.Àprésent,vouspouvezenannulerseulementunepartie.
La principale utilité de l’instruction ROLLBACK est de prévenir toutecorruption des données quand une transaction est interrompue par unecondition d’erreur. Annuler une transaction jusqu’à un certain point desauvegarden’aaucunsenssil’erreurs’estproduitependantledéroulementdelatransaction.Danscecas,vousvoulezévidemmentrestaurerlabasededonnéesdansl’étatquiétaitlesienavantledébutdecettetransaction.Maisvouspouvezavoird’autresraisonspouropéreruneannulationpartielle.
Supposons que vous effectuiez une série d’opérations complexes sur vosdonnées. En cours de route, vous récupérez des résultats qui vous font
comprendre que vous vous êtes engagé dans unemauvaise voie. Si vousavez placé une instruction SAVEPOINT juste avant d’emprunter cettepiste, vous pouvez annuler la transaction jusqu’au point de sauvegarde etessayer une autre direction. En supposant que le code était bon jusqu’aupointdesauvegarde,cettesolutionserabienplusefficacequed’effacerlatotalitédelatransactionpourtoutrecommenceràzéro.
Pour insérer un point de sauvegarde dans votre code SQL, utilisez lasyntaxesuivante:
SAVEPOINTnom_pointsauve;
Vous pouvez déclencher l’annulation jusqu’à un point de sauvegarde àl’aideducodesuivant:
ROLLBACKTOSAVEPOINTnom_pointsauve;
L’instruction SAVEPOINT n’est pas proposée dans toutes lesimplémentations.Vérifiezcequ’enditvotredocumentation.
ContraintesettransactionsIlne suffitpasdevérifierque lesdonnées sontdubon typepourgarantirqu’unebaseestvalide.Parexemple,lesvaleursnullessontinterditesdanscertaines colonnes, tandis que d’autres doivent contenir uniquement desvaleurs qui appartiennent à une certaine plage. J’aborde ces restrictions,égalementappeléescontraintes,auChapitre5.
Lescontraintesconcernentnaturellementlestransactions,carellespeuventvousempêcherdefairecequevousvoulez(aprèstout,ellessontd’ailleurslà aussi pour cela).Vous comptezpar exemple ajouter des données à unetable qui contient des colonnes sur lesquelles pèse la contrainte NOTNULL.Uneméthodecourante consiste à ajouterune lignevideà la table,puisàyinsérerplustarddesvaleurs.MaislacontrainteNOTNULLquipèse sur une colonne vous interdit d’employer cette stratégie. SQL nepermet pas d’ajouter une ligne qui contient une valeur nulle dans unecolonnesur laquellepèseunecontrainteNOTNULL, et cemêmesivouscomptez y stocker une valeur avant la fin de votre transaction. Pour
contourner ce problème, SQL vous permet de désigner les contraintescommeétantsoitDEFERRABLE,soitNOTDEFERRABLE.
LescontraintesNOTDEFERRABLEsontimmédiatementappliquées.Vouspouvezspécifierqu’unecontrainteDEFERRABLEestoubienDEFERREDoubienIMMEDIATE.SiunecontrainteDEFERRABLEestIMMEDIATE,elle fonctionnecommeunecontrainteNOTDEFERRABLE (elle est doncappliquée immédiatement). Si une contrainte DEFERRABLE estDEFERRED,ellen’estpasappliquéetoutdesuite.
Pourajouterdesenregistrementsvidesoueffectuertouteautreopérationquipeut violer des contraintes DEFERRABLE, vous pouvez utiliser uneinstructioncommecelle-ci:
SETCONSTRAINTSALLDEFERRED;
CetteinstructionchangetouteslescontraintesDEFERRABLEenconditionDEFERRED sans affecter les contraintes NOT DEFERRABLE. Une foisque vous avez effectué toutes les opérations susceptibles de violer voscontraintes,etquelatableatteintunétatquinelesviolepas,vouspouvezlesappliquerànouveauàl’aidedel’instructionsuivante:
SETCONSTRAINTSALLIMMEDIATE;
Sivousavezfaituneerreuretquel’unedevoscontraintesestactuellementviolée,vouslesaurezdèsl’exécutiondecetteinstruction.
Si vous ne spécifiez pas explicitement que vos contraintes DEFERREDsontIMMEDIATE, SQL le fera à votre place lorsque vous essaierez devalidervotre transactionparuneCOMMIT.Siuneviolationestdétectéeàce moment, la transaction ne sera pas validée et SQL vous renverra unmessaged’erreur.
La gestion des contraintes SQL vous protège contre la saisie de valeursinvalidestoutenvouspermettantd’enviolertemporairementcertainesdanslecadred’unetransactionactive.
L’exemplequisuitvousmontrecombienilestimportantdepouvoirdifférerl’applicationdescontraintes.
Supposez qu’une table EMPLOYES contienne les colonnes EMP_ NO,EMP_NOM,DEPT_NOetSALAIRE.DEPT_NOestunecléétrangèrequiréférence la table DEPT. Cette table DEPT est formée des colonnesDEPT_NOetDEPT_NOM;DEPT_NOestsacléprimaire.
Enplus,vousvoulezdisposerd’unetablesemblableàDEPTquicontienneune colonne TOTALPAIE, afin d’y enregistrer le total des valeursSALAIREpourlesemployésdechaquedépartement.
Vouspouvezcréerl’équivalentdecettetablesousformed’unevue,commececi:
CREATEVIEWDEPT2AS
SELECTD.*,SUM(E.SALAIRE)ASTOTALPAIE
FROMDEPTD,EMPLOYESE
WHERED.DEPT_NO=E.DEPT_NO
GROUPBYD.DEPT_NO;
Ilestégalementpossiblededéfinircettevueainsi:
CREATEVIEWDEPT3AS
SELECTD.*,
(SELECTSUM(E.SALAIRE)
FROMEMPLOYESE
WHERED.DEPT_NO=E.DEPT_NO)
ASTO-
TALPAIE
FROMDEPTD;
Mais supposons maintenant que, pour des raisons d’efficacité, vous nesouhaitiez pas calculer le total chaque fois que vous référencez DEPT.TOTALPAIE. En réalité, vous voudriez plutôt ajouter une vraie colonneTOTALPAIEdanslatableDEPT.Cettecolonneseraitmiseàjourlorsdechaquemodificationdesalaire.
Pourvousassurerque lacolonneSALAIREest fiable,appliquez-luiunecontraintedansladéfinitiondelatable:
CREATETABLEDEPT
(DEPT_NOCHAR(5),
DEPT_NOMCHAR(20),
TOTALPAIEDECIMAL(15,2),
CHECK(TOTALPAIE=(SELECTSUM(SALAIRE)
FROMEMPLOYESEWHEREE.DEPT_NO=
DEPT.DEPT_NO)));
À présent, vous voulez augmenter le SALAIRE de l’employé 123de100unités.Vousallezparexempleutiliserl’instructionsuivante:
UPDATEEMPLOYES
SETSALAIRE=SALAIRE+100
WHEREEMP_NO=‘123’;
Vousnedevezpasnonplusoublierd’actualiserlatableDEPT:
UPDATEDEPTD
SETTOTALPAIE=TOTALPAIE+100
WHERED.DEPT_NO=(SELECTE.DEPT_NO
FROMEMPLOYESE
WHEREE.EMP_NO=‘123’);
(Vous utilisez une sous-requête pour référencer le DEPT_NO del’employé123.)
Mais il reste un problème. Les contraintes sont contrôlées après chaqueinstruction. En principe, toutes les contraintes sont vérifiées. Dans lapratique, les implémentationsne testentque lescontraintesquiréférencentdesvaleursmodifiéesparl’instruction.
Après le premierUPDATE ci-dessus, l’implémentation vérifie toutes lesréférences dont les valeurs sontmodifiées par l’instruction, ce qui inclutcellequiestdéfiniedanslatableDEPT.Eneffet,cettecontrainteréférencela colonne SALAIRE de la table EMPLOYE et l’instruction UPDATEmodifiecettecolonne.Lacontrainteestvioléeaprès lepremierUPDATE.Vous supposez que la base de données est dans un état correct avant
l’exécution de l’instructionUPDATE, et que chaque valeurTOTALPAIEdelatableDEPTestégaleàlasommedesSALAIREcorrespondantsdelatableEMPLOYES.Mais cette égalité n’est plusvraiedèsque le premierUPDATE incrémente une valeur SALAIRE. La seconde instructionUPDATEcorrigecetteanomalieet remet labasededonnéesdansunétatoù la contrainte est vérifiée. Mais entre les deux instructions, cettecontrainteestbeletbienviolée.
L’instruction SET CONSTRAINTS DEFERRED vous permet dedésactiveroudesuspendretemporairementtoutesoucertainescontraintes.Lavérificationdecescontraintesestdifféréejusqu’àl’exécutiond’unSETCONSTRAINTS IMMEDIATE ou d’une instruction COMMIT ouROLLBACK.VouspouvezdoncdélimiterlesdeuxUPDATEprécédentspardesinstructionsSETCONSTRAINTS.Lecodeseprésentealorsainsi:
SETCONSTRAINTSDEFERRED;
UPDATEEMPLOYES
SETSALAIRE=SALAIRE+100
WHEREEMP_NO=‘123’;
UPDATEDEPTD
SETTOTALPAIE=TOTALPAIE+100
WHERED.DEPT_NO=(SELECTE.DEPT_NO
FROMEMPLOYESE
WHEREE.EMP_NO=‘123’);
SETCONSTRAINTSIMMEDIATE;
Cette procédure diffère l’application de toutes les contraintes. Si vousinsérez de nouvelles lignes dans DEPT, les clés primaires ne seront pasvérifiées.Vousvenezdoncde supprimeruneprotectiondontvouspouvezavoir besoin. Par conséquent, il vaut mieux nommer explicitement lescontraintesquevousvoulezdifférer:
CREATETABLEDEPT
(DEPT_NOCHAR(5),
DEPT_NAMECHAR(20),
TOTALPAIEDECIMAL(15,2),
CONSTRAINTPAIE_CONTRAINTE
CHECK(TOTALPAIE=SELECTSUM(SALAIRE)
FROMEMPLOYESE
WHEREE.DEPT_NO=DEPT.DEPT_NO));
Vouspouvezensuiteréférencerindividuellementvoscontraintes:
SETCONSTRAINTSPAIE_CONTRAINTEDEFERRED;
UPDATEEMPLOYES
SETSALAIRE=SALAIRE+100
WHEREEMP_NO=‘123’;
UPDATEDEPTD
SETTOTALPAIE=TOTALPAIE+100
WHERED.DEPT_NO=(SELECTE.DEPT_NO
FROMEMPLOYESE
WHEREE.EMP_NO=‘123’);
SETCONSTRAINTSPAY_EQ_SUMSALIMMEDIATE;
Si l’instruction CREATE ne contient aucun nom de contrainte, SQL engénère un implicitement. Ce nom implicite est stocké dans les tables duschéma(c’est-à-diredanslecatalogue).Toutefois, ilvautmieuxemployerdesnomsexplicites.Supposezmaintenantque,dans lasecondeinstructionUPDATE,vousavezspécifiéparerreurunevaleurd’incrémentde1000.Cettevaleurestautoriséedansl’instructionUPDATE,carl’applicationdela contrainte a été différée. Mais, lors de l’exécution de SETCONSTRAINTSIMMEDIATE, lescontraintesspécifiéessontcontrôlées.En cas d’échec,SETCONSTRAINTSprovoque une exception. Si vousexécutez une instruction COMMIT à la place de SET CONSTRAINTSIMMEDIATE et que les contraintes ne sont pas évaluées comme étanttoutesvérifiées,l’instructionCOMMITeffectueraunROLLBACK.
Rappelez-vous que vous ne pouvez différer l’application des contraintesquedanslecadred’unetransaction.Dèsquecettedernièreseterminesoitpar ROLLBACK, soit par COMMIT, les contraintes sont réactivées etvérifiées.Sivousutilisezcorrectementcetteméthode,vousnecréerezpas
de données qui violeraient une contrainte disponible pour d’autrestransactions.
L
Chapitre16UtiliserSQLdansdesapplications
DANSCECHAPITRE:
» UtiliserSQLdansuneapplication.
» CombinerSQLavecdeslangagesprocéduraux.
» Fairefaceauxincompatibilitésdelangage.
» IntégrerSQLdansuncodeprocédural.
» AppelerdesmodulesSQLdepuisuncodeprocédural.
» InvoquerSQLdepuisunoutilRAD.
esprécédentschapitresn’onttraitéquedeSQL.Desquestionsrelativesà la manipulation des données ont été soulevées et des requêtes SQLdéveloppéespoury répondre.Cetteméthodede travail, c’est-à-dire le
SQL interactif, permet d’apprendre tout ce que SQL peut faire mais necorrespondpasdutoutàlamanièredontSQLestutiliségénéralement.
Même si la syntaxe de SQL est proche de celle d’un langage naturel (enl’occurrence l’anglais), ce langage n’est pas facile àmaîtriser.La grandemajoritédesutilisateursd’ordinateursnesaittoujourspasutiliserSQL.Etil est probable que cette situation perdurera,même si ce livre devient unbest-seller.Dèsqu’unutilisateurlambdaseposeunequestionausujetdesbases de données, il ne pense certainement pas à s’asseoir devant sonterminal pour saisir une instruction SELECT. Ce travail est réservé auxanalystesetauxdéveloppeursd’applications,lesquelsnefontgénéralementpascarrièreensaisissantdesrequêtesadhocdansdesbasesdedonnéesàlongueur de journée. Ils développent des applications qui génèrent cesrequêtesàleurplace.
Si vous comptez effectuer une même tâche de manière répétitive, vousn’avezaucuneenviedelasaisirchaquefoisvialaconsole.Vouspréférerez
écrire une application qui exécute cette tâche de sorte que vous puissiezl’exécuterimmédiatementchaquefoisquevouslesouhaitez.SQLpeutainsiêtre intégré dans une application, mais il fonctionne alors d’unemanièrelégèrementdifférentedecellequenousavonspuvoirjusqu’àprésent.
SQLdansuneapplicationAu Chapitre 2, SQL est présenté comme un langage de programmationincomplet.Pourl’utiliserdansuneapplication,vousdevezlecombineràunlangage procédural tel que Visual Basic, C, C++, C#, Java, COBOL ouencorePython.LastructureparticulièredeSQLluiconfèredesavantagesetdesinconvénients.Leslangagesprocéduraux,quantàeux,ontunestructuredifférente,etdoncdifférentsavantagesetinconvénients.
Fort heureusement, les avantages de SQL tendent à compenser lesinconvénients des langages procéduraux. De même, les avantages deslangagesprocédurauxrésidentjustementlàoùSQLestfaible.Encombinantlesdeux,vous serezenmesuredecréerdesapplicationsparticulièrementefficaces. Il existe maintenant des environnements de développementd’application rapide orientés objet (RAD, Rapid ApplicationDevelopment), tels que Visual Studio de Microsoft ou l’environnementgratuitEclipse,qui incorporentducodeSQLdansvosapplicationsvia lamanipulationd’objetsplutôtquel’écrituredecodeprocédural.
Gardezunœilsurl’astérisqueDans les précédents chapitres, nous avons utilisé l’astérisque (*) commenotationabrégéesignifiant«touteslescolonnesdelatable».L’astérisqueest particulièrement utile si une table contient de nombreuses colonnes.Mais l’usage de ce caractère peut poser des problèmes lorsque vousintégrezduSQLdansuneapplication.
Une fois l’application écrite, une tierce personne (ou vous-même) peutajouter de nouvelles colonnes dans une table et/ ou en supprimerd’anciennes.Celapeutchanger lasignification«de toutes lescolonnes».L’applicationquiutilisel’astérisquepeutalorsrécupérerdescolonnesbiendifférentesdecellesqu’elleattendait.
Cetypedemodificationd’unetablen’affectepaslesprogrammesexistantstantqu’ilsn’ontpasétérecompiléssoitpourcorrigerunbogue,soitpouren
modifiercertainesfonctionnalités(cequipeutneseproduirequeplusieursmois plus tard). L’effet du caractère « * » est alors étendu à toutes lescolonnes actuelles de la table, ce qui peut provoquer un plantage del’applicationpourunetoutautreraisonquel’objetdelarecompilation.Etlecauchemarcommence...
Pour éviter ce type de problème, n’utilisez pas l’astérisque et spécifiezexplicitementlenomdetouteslescolonnesdansl’application.
ForcesetfaiblessesdeSQLSQL est parfaitement adapté à la récupération des données. Si desinformations importantes sont enterrées quelquepart dans une table d’unebasededonnées,SQLvous fournira tous lesoutilsdontvousavezbesoinpourlesretrouver.Vousn’avezpasbesoindeconnaîtrel’ordredeslignesetdes colonnes dans une table, car SQL ne manipule pas ces objetsindividuellement. Les fonctionnalités transactionnelles de SQL vousgarantissent que vos opérations sur la base de données ne seront pasaffectées par des accès simultanés aux tables que vous êtes en train demanipuler.
Parcontre,l’undesprincipauxinconvénientsdeSQLestlarusticitédesoninterfaceutilisateur.SQLneproposerienpourprésenteragréablementdesécrans de saisie ou des rapports. Il accepte des commandes en modeconsoleetretournedesvaleurssurl’écranduterminalligneaprèsligne.
Parfois,uneforcedansuncertaincontextepeuts’avérerunefaiblessedansunautre.L’undesavantagesdeSQLestsacapacitéàopérersurunetableentière en une fois.Une seule instructionSELECTpeut traiter toutes lesdonnées d’une table, que celle-ci contienne une ligne ou des centaines,voiredesmilliersdelignes.Cependant,SQLn’estpastrèsàl’aiselorsqu’ils’agit de manipuler une ligne en particulier, ce qui peut constituer unproblème si c’est ce que vous souhaitez faire.Dans ce cas, vous pouvezutiliserlescurseursdeSQLoufaireappelàunlangageprocéduralhôte.
Forcesetfaiblessesdeslangagesprocéduraux
Contrairement àSQL, les langages procéduraux sont conçus pour réaliserdes opérations ligne par ligne, ce qui permet au développeur del’application de contrôler très précisément le traitement appliqué à unetable.Cecontrôlefinestunedesgrandesforcesdeslangagesprocéduraux.Toutefois, c’est aussi l’un de leurs principaux inconvénients. Ledéveloppeurdoiteneffetsavoirexactementoùsontstockéeslestablesdanslabasededonnées.L’ordredeslignesetdescolonnesestimportantetdoitêtreprisencompte.
Dufaitdeleurnature«étapeparétape»,leslangagesprocédurauxoffrentune grande souplesse quant à la création d’écrans de saisie et devisualisationdesdonnées.Ilsvouspermettentégalementdeprocéderàdesimpressionssophistiquéesderapports.
ProblèmesliésàlacombinaisondeSQLetd’unlangageprocéduralÉtantdonnéquelesforcesdeSQLcompensentlesfaiblessesdeslangagesprocéduraux et vice versa, il paraît cohérent d’associer les deux pouradditionner leurs avantages sans être pénalisé par leurs faiblessesrespectives.Maisaussiintéressantequesoitcettecombinaison,elleestloind’êtresimpleàmettreenœuvre.Vousdevrezsurmontercertainschallengesavantd’enarriveraumariageparfait.
DifférencedesmodesopératoiresUndesgrandsproblèmesposésparlacombinaisondeSQLetd’unlangageprocéduralestqueSQLmanipuledes tablesentières tandisqu’un langageprocéduraltraiteuneligneàlafois.Parfois,ceproblèmeestmineur.Vouspouvezdifférencier les opérationsqui s’appliquent à des tables de cellesquiconcernentdeslignesenfaisantappelauxoutilsappropriés.
Maisvousrisquezd’avoirunproblèmesivousvoulezrechercherdansunetable lesenregistrementsqui répondentàcertainscritères,puis traitercesenregistrementsdedifférentesmanières selonqu’ils répondentounonauxconditions. Un tel processus requiert à la fois la puissance de SQL pourrécupérer les données et les fonctionnalités du langage procédural pourtraiterlesconditions.VouspouvezsimplementintégrerdesinstructionsSQLàdesemplacementsstratégiquesd’unprogrammequevousavezécritdans
un langage procédural (nous allons revenir un peu plus loin sur cettequestion).
IncompatibilitésdestypesdedonnéesL’intégrationdeSQLdansun langageprocéduralestconfrontéeàunautreproblème : les types de données de SQL sont différents de ceux qui sontutilisésparleslangagesprocédurauxlesplusrépandus.Celan’arienensoidetrèssurprenant,puisquelestypesdedonnéesdiffèrentdetoutemanièred’unlangageprocéduralàunautre.
Iln’existeaucunestandardisationdestypesdedonnéespourleslangagesdeprogrammation.Avantlaversion92deSQL,l’incompatibilitédestypesdedonnées posait un problème majeur. Mais depuis SQL-92 (et sessuccesseurs), l’instructionCASTpermet de résoudre cette difficulté. LeChapitre 9 explique en détail comment vous pouvez utiliserCAST pourconvertirdestypesdedonnéesd’unlangageprocéduralenuntypereconnuparSQL,pourvuqu’ilyaitcompatibilitéentrelasourceetladestination.
UtiliserSQLdansdeslangagesprocéduraux
Mêmesil’intégrationdeSQLdansdeslangagesprocédurauxseheurteàdenombreuses difficultés, elle n’en reste pas moins possible. En fait, vousdevezmêmeprocéderdecettemanièredansdenombreuxcas,dèslorsqu’ilvousfautproduirelesrésultatsvoulusdansletempsimparti.Vousdisposezmême pour cela de plusieurs méthodes. La section suivante en proposetrois:SQLintégré,lelangagedemoduleetlesoutilsRAD.
SQLintégréLasolutionadoptéepourcombinerducodeSQLetducodeécritdansunlangageprocéduralest leSQLintégré.Vousvousdemandezcommentcelapeutfonctionner?C’estaussisimplequecequevouslisez:lesinstructionsSQLsontparachutéesenpleinmilieudulangageprocédurallàoùilyenabesoin.
Commevouslesavez,uneinstructionSQLquisurgitsoudainementaubeaumilieud’unprogrammeCpeutposerunproblèmeaucompilateurquines’yattendpas.C’estpourquoi lesprogrammesquicontiennentduSQLintégrésont généralement traités par un préprocesseur avant d’être compilés ouinterprétés.LepréprocesseurestavertidelaprésencedecodeSQLparladirectiveEXECSQL.
ExaminonsunprogrammeécritdanslaversionPro*Cd’OracledulangageC.Cette petite application accède à la table des employés d’une société,demande à l’utilisateur de saisir un nom, puis affiche le salaire et lacommissiondecetemployé.Elleproposealorsàl’utilisateurdesaisirdenouvelles valeurs pour le salaire et la commission, après quoi ellemet àjourlatableaveclesvaleursactualisées:
EXECSQLBEGINDECLARESECTION;
VARCHARuid[20];
VARCHARpwd[20];
VARCHARenom[10];
FLOATsalaire,comm;
SHORTsalaire_ind,comm_ind;
EXECSQLENDDECLARESECTION;
main()
{
intsret;/*coderetourdescanf*/
/*Connexion*/
strcpy(uid.arr,”FRED”);/*Copierlenomde
l’utilisateur
*/
uid.len=strlen(uid.arr);
strcpy(pwd.arr,”TOWER”);/*Copierlemotde
passe*/
pwd.len=strlen(pwd.arr);
EXECSQLWHENEVERSQLERRORSTOP;
EXECSQLWHENEVERNOTFOUNDSTOP;
EXECSQLCONNECT:uid;
printf(“Utilisateurconnecté:\n“,uid.arr);
printf(“Saisissezlenomdel’employéàmodifier
:“);
scanf(“%s”,ename.arr);
ename.len=strlen(ename.arr);
EXECSQLSELECTSALAIRE,COMMINTO:salaire,:comm
FROMEMPLOYES
WHEREENOM=:enom;
printf(“Employe:pourcentagessalaire:%6.2f
comm:%6.2f
\n”,
enom.arr,salaire,comm);
printf(“Saisissezlenouveausalaire:“);
sret=scanf(“%f”,&salaire);
salaire_ind=0;
if(sret==EOF!!sret==0)/*Positionner
l’indicateur
*/
salaire_ind=-1;/*Positionnerl’indicateurpour
NULL*/
printf(“Saisissezlanouvellecommission:“);
sret=scanf(“%f”,&comm);
comm_ind=0;/*Positionnerl’indicateur*/
if(sret==EOF!!sret==0)
comm_ind=-1;/*Positionnerl’indicateurpour
NULL*/
EXECSQLUPDATEEMPLOYES
SETSALARIE=:salaire:salaire_ind
SETCOMM=:comm:comm_ind
WHEREENOM=:enom;
printf(“Employé%smodifié.\n”,enom.arr);
EXECSQLCOMMITWORK;
exit(0);
}
Nulbesoind’êtreunexpert enCpour comprendre àquoi sert ce codeetcommentillefait.Résumonstoutdemêmeledéroulementdesinstructionsci-dessus:
1. SQLcommencepardéclarerdesvariableshôtes.
2. LecodeCcontrôlelaséquencedeconnexionde
l’utilisateur.
3. SQLmetalorsenplacelagestiond’erreursetseconnecteà
labasededonnées.
4. LecodeCdemandelenomd’unemployéetlestockedans
unevariable.
5. UneinstructionSQLSELECTrécupèrelesalaireetla
commissiondel’employéainsidésignéetlesstockedans
lesvariableshôtes:salaireet:com.
6. LecodeCreprendlamainetaffichelenomdel’employé,
sonsalaireetsacommission,puisdemandeàl’utilisateur
desaisirlesnouvellesvaleursdusalaireetdela
commission.Ilvérifiequelasaisieaétéeffectuée.Siellene
l’apasété,ilpositionneunindicateur.
7. LeSQLmetàjourlabasededonnéesaveclesnouvelles
valeurs.
8. LeCaffichealorslemessageindiquantquel’opérationest
terminée.
9. Enfin,leSQLvalidelatransactionetleCmetfinau
programme.
Le préprocesseur vous permet de combiner des commandes des deuxlangages.IlséparelesinstructionsSQLdesinstructionsdulangagehôteen
lesstockantdansuneroutineexterne.ChaqueinstructionSQLestremplacéepar un appel (CALL) du langage hôte vers cette routine externe. Lecompilateurdulangagepeutalorsfairesontravail.
LamanièredontlecodeSQLesttransmisàlabasededonnéesdépenddel’implémentation. En tant que développeur, vous n’avez pas à vouspréoccuperdecettequestion.C’estlepréprocesseurquis’encharge.
DéclarerdesvariableshôtesLe programme écrit dans le langage hôte et les segments SQLont besoind’échangerdes informations.Pour cela, il vous faututiliserdesvariableshôtesquevousdevezdéclareravantd’yfaireappel,sansquoiSQLnelesreconnaîtrapas.Cesdéclarations sont inclusesdansunsegmentdéclaratifqui précède le segment programme.Elles sont annoncées par la directivesuivante:
EXECSQLBEGINDECLARESECTION;
Lafindusegmentdéclaratifestsignaléepar:
EXECSQLENDDECLARESECTION;
TouteinstructionSQLdoitêtreprécédéedeladirectiveSQLEXEC.Lafind’unsegmentdéclaratifpeutéventuellementêtresignaléeparunedirectivedeterminaison.EnCOBOL,cettedirectivedeterminaisonestEND-EXEC.EnC,ils’agitd’unpoint-virgule.
ConvertirdestypesdedonnéesEnfonctiondudegrédecompatibilitédestypesdedonnéesdulangagehôteet ceux de SQL, vous allez recourir si nécessaire àCAST pour réalisercertaines conversions.Vous pouvez utiliser pour cela des variables hôtesqui ont été déclarées dansDECLARESECTION.N’oubliez pas de faireprécéder le nom de la variable hôte d’un deux-points ( : ) lorsque vousl’employezdansdesinstructionsSQL.Parexemple:
INSERTINTOALIMENTS
(NOM,CALORIES,PROTEINES,GRAISSES,
HYDRATECARBONE)
VALUES
(:nom,:calories,:protéines,:graisses,
:carbo);
LangagedemoduleLe langage de module est une autre solution pour utiliser SQL avec unlangage procédural. Avec ce type de langage, vous stockez explicitementtoutesvosinstructionsSQLdansunmoduledistinct.
Unmodule SQL est tout simplement une liste d’instructionsSQL.Chaqueinstruction est incluse dans une procédure SQL et est précédée d’unespécificationdunomdelaprocédureainsiquedunombreetdutypedesesparamètres.
Chaque procédure SQL contient une seule instruction SQL. Dans leprogramme hôte, vous appelez explicitement la procédure là où vouscomptez exécuter l’instruction SQL qu’elle contient. Tout se passe donccommes’ils’agissaitd’unsous-programmeécritdanslelangagehôte.
L’utilisationdemodulesSQLrevientenquelquesorteàeffectueràlamainletravaildupréprocesseur.
LeSQL intégré est bienplus souvent utilisé que laméthode« langagedemodule ». La plupart des éditeurs proposent une forme de langage demodule, mais peu insistent sur le sujet dans leur documentation. Leslangagesdemoduleprésententplusieursavantages:
» LesprogrammeursenSQLn’ontpasbesoind’êtreen
plusdesspécialistesd’unlangageprocédural.Comme
SQLestcomplètementisolédulangageprocédural,vous
pouvezlouerlesservicesdesmeilleursdéveloppeursSQL
pourécrirelecodedevosmodules(qu’ilssoientounon
familiarisésavecvotrelangageprocédural).Enfait,ilest
mêmepossiblededifférerlechoixd’unlangageprocédural
jusqu’àcequevosmodulesSQLsoientécritsetdébogués.
» Vouspouvezlouerlesservicesdesmeilleurs
développeurspourvotrelangageprocédural,même
s’ilsn’yconnaissentrienenSQL.L’idéeestsimple:sivos
technogourousSQLn’ontpasbesoind’êtredesexpertsdu
langageprocédural,laréciproqueestaussivraie.
» SQLn’estpasmélangéaucodeprocédural,sibienque
vouspouvezutiliserledébogueurdevotrelangage
procédural.Celapeutvousfairegagneruntemps
considérablededéveloppement.
Encore une fois, un avantage vu sous un certain angle peut s’avérer uninconvénientd’unautrepointdevue.CommelesmodulesSQLsontséparésdu code procédural, il n’est pas si facile de suivre le fil logique del’applicationlorsquevousessayezd’encomprendrelefonctionnement.
DéclarationsdansunmoduleLasyntaxedesdéclarationsdansunmoduleàemployerestlasuivante:
MODULE[nom-module]
[NAMESAREnom-jeu-caractères]
LANGUAGE
{ADA|C|COBOL|FORTRAN|MUMPS|PASCAL|PLI|SQL}
[SCHEMAnom-schéma]
[AUTHORIZATIONid-autorisation]
[declarations-tables-temporaires...]
[declarations-curseurs...]
[declarations-curseurs-dynamiques...]
procédures...
Commel’indiquentlescrochets,lenomdumoduleestoptionnel.Toutefois,ilestpréférabledelenommer,neserait-cequepourévitertouteconfusiondanslecode.
LaclauseoptionnelleNAMESAREspécifieunjeudecaractères.Sivousnespécifiezpascetteclause,c’estlejeudecaractèrespardéfautdevotreimplémentation SQL qui sera utilisé. La clause LANGUAGE indique aumodulequelestlelangagequil’appellera.Lecompilateurdoitdisposerdecette information, car il doit faire croire au programme appelant que lesinstructions SQL ne sont qu’un sous-programme écrit dans son proprelangage.
Bienque lesclausesSCHEMAetAUTHORIZATIONsoient facultatives,vousdevezspécifieraumoinsl’uned’entreelles(oulesdeux).LaclauseSCHEMA spécifie le schéma par défaut et la clause AUTHORIZATIONconcernel’identifiantdel’autorisation.Cetidentifiantétablitlesprivilègesdontvousdisposez.Sivousneprécisezrien,leSGBDutiliseral’identifiantassocié à votre session pour déterminer les privilèges attribués à votremodule.Sivousn’avezpaslesprivilègesrequispoureffectuerl’opérationappeléeparvotreprocédure,cettedernièreneserapasexécutée.
Sivotreprocéduredoitutiliserdes tables temporaires, spécifiez-les avecune clause de déclaration de table temporaire. Déclarez de même lescurseurs et les curseurs dynamiques avant toute procédure qui les utilise.Déclareruncurseuraprèsuneprocédureestautoriséàpartirdumomentoùladiteprocéduren’utilisepasleditcurseur.
LesprocéduresdumoduleEnfin, après toutes ces déclarations se trouve une liste de procédures. Ils’agit de la partie fonctionnelle du module. Une procédure comporte unnom,desdéclarationsdeparamètresetdesinstructionsSQLexécutables.Lelangage procédural appelle la procédure par son nom et lui passe desvaleurs par l’intermédiaire des paramètres déclarés. La syntaxe d’uneprocédureestlasuivante:
PROCEDUREnom-procédure
(déclaration-paramètre[,déclaration-paramètre
]...)
SQLinstruction;
[SQLinstructions];
Ladéclarationd’unparamètredoitprendrelaformesuivante:
nom-paramètretype-de-données
ou:
SQLSTATE
Lesparamètresquevousdéclarezpeuventêtredesparamètresd’entrée,desparamètresdesortieoulesdeuxàlafois.SQLS-TATEestunparamètredestatutservantàrapporterleserreurs.
OutilsRADorientésobjetsSi vous utilisez des outils RAD évolués, vous pouvez développer desapplicationscomplexessansavoiràécrireunelignedecodeenC++,C#,Python,Javaoutoutautrelangageprocédural.Ilvoussuffitdechoisirdesobjetsdansunelibrairieetdelesplacervisuellementàl’écran.
Lesobjetspossèdentdespropriétésquilescaractérisentetsontassociésàdesévénementsappropriésàleurtype.Vouspouvezégalementassocieruneméthodeàunobjet.Uneméthodeestuneprocédureécritedansunlangageprocédural.Maisvouspouvezconstruiredesapplicationsutilessansécrireuneseuleméthode.
Bienquevouspuissiezcréerdesapplicationscomplexessansrecouriràunlangageprocédural,vousaurezprobablementtôtoutardbesoindeSQL.Eneffet, il est difficile, voire impossible, de reproduire la richessed’expressiondeSQLdansunmondeorientéobjet.C’estpourquoilesoutilsRADélaborésproposentunmécanismepourinjecterdesinstructionsSQLdansvosapplicationsorientéesobjet.VisualStudiodeMicrosoftenestunexemple. Access de Microsoft est un autre environnement dedéveloppement d’applications qui vous permet d’utiliser SQL encombinaisonavecsonlangageprocédural,VBA.
LeChapitre4vousmontrecommentcréerdes tablesdebasesdedonnéesavec Access. Naturellement, cette opération ne représente qu’une faiblepartiedespossibilitésd’Access.Celui-ciestunoutilquisertavant toutàréaliserdesapplicationsdestinéesàtraiterlesdonnéesextraitesdestablesde vos bases de données. En utilisant Access, le développeur positionnedesobjetssurdesformulaires,puispersonnalisecesobjetsenleurdonnantdes propriétés, des événements et des méthodes. Ces formulaires et
méthodes sontensuitemanipulésparducodeVBAcapabled’intégrerdesinstructionsSQL.
BienquelesoutilsRADtelsqu’Accesspuissentpermettredeproduireenpeu de temps des applications de grande qualité, ils sont généralementspécifiquesàuneplate-forme.Parexemple,Accessnefonctionnequesouslesystèmed’exploitationWindowsdeMicrosoft.Nel’oubliezpassivousenvisagezunjourd’écriredesfonctionnalitésindépendantesdusupport,ouencoredemigrervosapplicationsversd’autresplates-formes.
Les outils RAD tels qu’Access sont les premiers fruits d’un possiblerapprochement entre les approches relationnelles et orientées objet desbases de données. SQL et les avantages offerts par les structuresrelationnelles survivront tous deux. Ils bénéficieront des capacités dedéveloppement rapide (et comparativement moins sujet aux erreurs)apportéesparlaprogrammationorientéeobjet.
UtiliserSQLavecMicrosoftAccessMicrosoft Access cible essentiellement les personnes qui souhaitentdévelopper des applications relativement simples sans se soucierparticulièrementdeprogrammation.Sitelestvotrecas,voustrouverezdanslacollection«Pour lesNuls»dequoi répondreàvosbesoins !Sivousvoulezallerplusloinenassociantlelangageprocédurald’Access(VBA)etSQL, la remarqueprécédente est encoreplus vraie, tant la documentationlivrée par Microsoft est limitée sur ce sujet. Mais attention :l’implémentation SQL que vous trouvez dans Access est loin d’êtrecomplète, et il vous faudra tout le flair d’un Sherlock Holmes pour ladébusquer.
Dans leChapitre3, j’aidécrit les troiscomposantsdeSQL:le langagededéfinitiondedonnées(DDL),lelangagedemanipulationdedonnées(DML)et le langage de contrôle des données (DCL). Le sous-ensemble de SQLcontenudansAccessimplémenteuniquementlapartieDML.Lesopérationsde création des tables sont réalisées à l’aide de l’outilRADprésenté auChapitre 4. La même technique est employée pour l’implémentation desmesuresdesécurité(ellessonttraitéesauChapitre14).
Pour voir un coin de SQL sous Access, il est nécessaire de souleverquelquepeulevoileposéparleRAD.Prenonsàtitred’exempleunebasede données censée être gérée par une organisation non gouvernementale(fictive) : la SEL (Société pour l’écologie lunaire). Cette organisation
comprend plusieurs équipes de recherche, dont notamment la célèbreERBALU(Equipederecherchedelabaselunaire).Unegravequestionsepose:quellessontlescommunicationssavantesécritesparlesmembresdecetteéquipe?Pouryrépondre,unerequêteaétéformuléeenfaisantappelau mode QBE d’Access (requête par l’exemple). Cette requête, qui estillustréesurlaFigure16.1, récupère les informationsvouluesàpartirdestablesEQUIPES-RECHERCHE,AUTEURSetARTICLES,avecl’aidedetablesde recoupage (AUT_ARTetAUT_RECH)quiontétéajoutéesafindecouperlesrelationsplusieursàplusieurs.
Après avoir cliqué sur l’ongletAccueil pour accéder à la barre d’outils,vous pouvez cliquer sur le menu déroulant de l’icône Vue dans l’anglesupérieur gauche de la fenêtre pour révéler les autres types de vuesdisponibleslorsdelacréationderequêtes.L’undeschoixproposésestlemodeSQL(voirlaFigure16.2).Lorsquevousactivezcemode,lafenêtrede l’éditeur SQL apparaît. Elle affiche l’instruction SQL générée parAccessàpartirdeschoixopérésdansl’interfacegraphique.
FIGURE16.1ConceptiondelarequêteArticlesERBALUenmodeCréation.
FIGURE16.2LavueSQLestproposéedanslalistedesaffichages.
L’instructionSQLmontréesurlaFigure16.3estcellequiesteffectivementenvoyée au moteur de la base de données. Ce moteur, qui s’interfacedirectement avec la base, ne comprend que le langage SQL. Tout ce quevous entrez dans lemode ditCréation d’Access est traduit en SQL avantenvoipourtraitementaumoteurdelabasededonnées.
FIGURE16.3UneinstructionSQLquisertàretrouverlesnomsdetouslesarticles
écritspardesmembresdel’équipeERBALU.
Vousavezpeut-êtreremarquéquelasyntaxedel’instructionillustréesurlaFigure 16.3 diffère quelque peu de celle du standard SQL ANSI/ISO.Souvenez-vous du proverbe : « Quand tu es à Rome, vis comme lesRomains.»LorsquevoustravaillezavecAccess,utilisezsondialecteSQL.Ceconseilvautd’ailleursquelquesoit l’environnementdans lequelvoustravaillez.TouteslesimplémentationsSQLdivergentdustandardsurteloutelaspect.
Si vous voulez écrire directement une requête dans le SQL d’Access(autrementdit,sanspasserparlemodedecréationgraphique),ilvoussuffitd’effacerlecontenucourantdelafenêtred’éditionetdesaisirunenouvelleinstructionSELECT.Cliquezensuitesurleboutondelabarred’outilsquiafficheunpoint d’exclamationpour exécuter votre requête.Le résultat vaapparaîtrepardéfautsouslaformed’unefeuillededonnées.
VUtiliserSQLdanslemonderéel
DANSCETTEPARTIE:
UtiliserODBC.
UtiliserJDBC.
TravaillersurdesdonnéesXML.
C
Chapitre17ODBCetJDBC
DANSCECHAPITRE:
» Définitiond’ODBC.
» Descriptiondesdiversespartiesd’ODBC.
» Utilisationd’ODBCdansunenvironnementclient/serveur.
» UtiliserODBCsurInternet.
» UtiliserODBCsurunintranet.
» UtiliserJDBC.
esdernièresannées,l’interconnexiondesordinateurss’estmassivementdéveloppée, aussi bien dans les organisations qu’entre elles. Cetteconnectivitéfrénétiqueaengendrélebesoindepartagersurlesréseaux
lesinformationsfourniesparlesbasesdedonnées.Leprincipalobstacleaulibre partage de l’information sur les réseaux est l’incompatibilité dessystèmesd’exploitationetdesapplicationsquifonctionnentsurdifférentesmachines.Cet obstacle a été en partie contourné par la création de SQL,puisparlesévolutionsquil’ontfaitprogresseraufildesannées.
Hélas!LeSQL«standard»n’estpasvéritablementunstandard.MêmeleséditeursdeSGBD,quisedisentconformesaustandardinternationalSQL,ont inclus dans leur implémentation de SQL des fonctionnalités qui lesrendent incompatibles avec les extensions propriétaires desimplémentations d’autres éditeurs. Et tous rechignent à abandonner leurspropresextensions,carleursclientslesutilisentdansleursapplicationsetensontdevenusdépendants.Ilfautdonctrouveruneautrevoiepourassurerla communication entre SGBD, un outil qui n’oblige pas les éditeurs à«nivelerparlebas»leursimplémentationsjusqu’àatteindreunpluspetitdénominateur commun. Cette solution, c’est ODBC (Open DataBaseConnectivity).
ODBCODBC est une interface standard entre une base de données et uneapplication qui accède au contenu de cette base. Recourir à ce standardpermet à un front end applicatif d’accéder à n’importe quelle base dedonnéesenutilisantSQL.Laseuleconditionestquefrontendetbackendadhèrent tous deux au standard ODBC, dont la version courante estODBC4.0.
Une application accède à une base en utilisant un pilote (ou driver)spécifiquementconçupours’interfaceraveccettedernière.Lefrontenddupilote, c’est-à-dire la partie qui se connecte à l’application, se conformescrupuleusementaustandardODBC.Ilprésentetoujourslamêmeinterfaceà l’application, et cequelque soit lemoteurde labasededonnéesqu’ilpermetd’attaquer.Lebackenddupiloteestconçupourdialogueravecuntypespécifiquedemoteurdebasededonnées.Grâceàcettearchitecture,lesapplicationsn’ontplusbesoind’êtremodifiéesenfonctiondumoteurdebasededonnéesquicontrôlelesdonnéesquecesapplicationsmanipulent.Toutela«machinerie»interneestmasquée.
L’interfaceODBCL’interfaceODBC est essentiellementun ensemblededéfinitions reconnucomme étant un standard. Ces définitions concernent tout ce qui doit êtreprisencomptepourétablirunecommunicationentrel’applicationetlabasededonnées.
L’interfaceODBCdéfinitlesélémentssuivants:
» Unelibrairied’appelsdefonction.
» UnesyntaxeSQLstandard.
» DestypesdedonnéesSQLstandard.
» Unprotocolestandardpourseconnecteràunmoteur
debasededonnées.
» Descodesd’erreurstandard.
Lesappelsde fonctionODBCpermettentde se connecter àunmoteurdebase de données, d’exécuter des instructions SQL et de renvoyer lesrésultatsproduitsàl’application.
Poureffectueruneopérationsurlabasededonnées,vousdeveztransmettreen argument l’instruction SQL appropriée à un appel de fonctionODBC.Tant que vous utilisez la syntaxe SQL standard comprise par ODBC,l’opérationfonctionne,indépendammentdumoteurdebasededonnéesquevousattaquez.
Lescomposantsd’ODBCL’interface ODBC est composée de quatre couches fonctionnelles quis’intercalent de la manière suivante entre l’utilisateur et les données surlesquelles il souhaite travailler (le but étant d’assurer une communicationtransparente entre n’importe quel front end compatible et n’importe quelbackendcompatible):
» L’application:C’estlapartiedel’interfaceODBClaplus
prochedel’utilisateur.L’applicationdoitêtreinformée
qu’ellecommuniqueavecunesourcededonnéesvia
ODBC.ElledoitseconnecterendouceuraupiloteODBCen
respectantscrupuleusementcestandard.
» Legestionnairedupilote:Ils’agitd’uneDLL(Dynamic
LinkLibrary)généralementfournieparMicrosoft.Le
gestionnairechargelespilotesquicorrespondentaux
sourcesdedonnéesdusystème(ilpeutyenavoir
plusieurs)etdirigelesappelsdefonctionprovenantde
l’applicationverslessourcesdedonnéesadéquatesviales
pilotesadaptés.Cegestionnairetraiteaussidirectement
certainsappelsdefonctionODBC.Enfin,ildétecteetgère
certainstypesd’erreurs.
» Lepilote:Commelessourcesdedonnéespeuventêtre
différenteslesunesdesautres(etsouventtrèsdifférentes),
vousdeveztrouverunmoyendetraduirelesappelsde
fonctionODBCdanslelangagenatifquecomprendchaque
source.CettetraductionestassuréeparlaDLLdupilote.
ChaqueDLLdepilotereçoitdesappelsdefonctionvia
l’interfacestandardODBCetlestranscritdansuncodeque
sasourcededonnéespeutcomprendre.Lorsquecette
sourceretourneunrésultat,lepilotelereformatedans
l’autresensafindeproduiteunrésultatconformeau
standardODBC.Lepiloteestl’élémentcléquipermetaux
applicationscompatiblesODBCdemanipulerlastructure
etlecontenudesourcesdedonnéeselles-mêmes
compatiblesODBC.
» Lasourcededonnées:Ellepeutêtredenature
différente.CepeutêtreunSGBDrelationnel(etsabasede
donnéesassociée)quirésidesurlemêmeordinateurque
l’application.Cepeutêtreégalementunebasededonnées
surunordinateurdistant.Ilpeutaussis’agird’unfichier
ISAM(IndexedSequentialAccessMethod,méthoded’accès
séquentielleindexée)sansSGBDassocié,etquisetrouve
soitsurunordinateurlocal,soitsurunsystèmedistant.
Quellequesoitlaformequeprendlasourcededonnées,
vousdevezdisposerd’unpilotespécifiquepour
communiqueravecelle.
ODBCdansunenvironnementclient/serveurDans un environnement client/serveur, l’interface entre le client et leserveur est appeléeAPI (Application Programming Interface, interface deprogrammationd’application).UnpiloteODBC,parexemple,contientune
API. UneAPI peut être propriétaire ou standard. Dans le cas d’une APIpropriétaire,lapartieclientdel’interfaceaétéspécifiquementconçuepourfonctionner avec un back end particulier sur le serveur. Le code quiconstituecette interfaceestunpilote,égalementappelépilotenatif surunsystème propriétaire. Un pilote natif est optimisé pour ne fonctionnerqu’avecunclient spécifiqueet sa sourcededonnées associée.Du faitdecettespécialisation,lespilotesnatifsonttendanceàtransmettrecommandesetinformationsbeaucoupplusvite,avecunminimumdedélaid’attentelorsdechaqueopération.
Sivotresystèmeclient/serveuraccèdetoujoursaumêmetypedesourcededonnées,etquevousêtescertaindenejamaisavoird’autresbesoins,vouspouvezutiliserlepilotenatiffourniavecvotreSGBD.Parcontre,sivouspensezquevousdevrezunjouraccéderàdessourcesdedonnéesd’untypedifférent,utilisezuneAPIODBCpouréviterdedevoirrecommencerplustardvotretravail.
Les pilotes ODBC sont également optimisés pour travailler avec dessourcesdedonnéesspécifiques,maisilsprésententtouslamêmeinterfaceaugestionnairedepilote.Unpilotequin’apasétéoptimisépourunfrontend particulier n’est probablement pas aussi rapide qu’un pilote natifspécialement conçu pour ce front end. L’un des inconvénients des pilotesODBCdepremièregénérationétaitqu’ilsétaientpeuperformantscomparésauxpilotesnatifs.Toutefois,destestsrécentsontdémontréquelespilotesODBC4.0sontdevenusbienpluscompétitifs.LatechnologieODBCestàce pointmature qu’il n’est plus nécessaire de sacrifier la standardisationsurl’auteldesperformances.
ODBCetInternetLesopérationssurunebasededonnéessonttrèsdifférentessurInternetetsurunsystèmeclient/serveur.Dupointdevuedel’utilisateur,ladifférencela plus visible réside dans la partie client du système (qui comprendl’interface utilisateur). Dans le cas d’un système client/serveur, cetteinterfaceestlapartied’uneapplicationquicommuniqueaveclasourcededonnées hébergée par le serveur via des instructions SQL compatiblesODBC. Sur le World Wide Web, la partie client du système est unnavigateurWebquicommuniqueaveclasourcededonnéeshébergéesurleserveur via HTML (HyperText Markup Language, langage de baliseshypertexte).
Denosjours,HTMLn’estplusleseullangageduWeb.Maiscelanechangeenriennotrepropos.
Toute personne pourvue d’un navigateurWebpeut accéder à des donnéesdisponiblessurleWeb.Lefaitdemettreenligneunebasededonnées(ondit aussi publier) offre de nombreux avantages, surtout si vous voulezpartager des informations en dehors de votre réseau local.Malheureusement, vous ne disposez généralement pas d’un contrôle trèsstrict sur lapersonnalité des internautes…C’est pourquoimettre en lignedesbasesdedonnéesrevientplusàpublierdesinformations–sous-entendupour le monde entier – qu’à les partager – sous-entendu avec quelquescollèguesdetravail.Pourautant,cen’estpasparcequevotrenavigateurestcapabled’accéderàdesdonnéessur leWebqu’ilsaitquoienfaire.Pourplus de précisions sur ce point, voyez un peu plus loin la section « Lesextensionsclient».LaFigure17.1 illustre la comparaison entre systèmesclient/serveuretsystèmess’appuyantsurleWeb.
FIGURE17.1Systèmeclient/serveurversussystèmedebasededonnéessurleWeb.
LesextensionsserveurDansun systèmeWeb, la communicationentre lenavigateurqui se trouvesurleposteclientetleserveurWebquisetrouvesurunemachinedistante
s’effectue en HTML. Un composant système appelé extension serveurtraduitleHTMLenSQLcompatibleODBC.Leserveurdebasededonnéesagit sur ce code SQL, qui attaque à son tour directement la source dedonnées.Dansladirectioninverse,lasourcededonnéesrenvoielerésultatgénéré par une requête à l’extension serveur via le serveur de base dedonnées. L’extension se charge de transformer ce résultat dans une formequeleserveurWebestcapabledegérer.Lesréponsessontalorsenvoyéesvia le Web au navigateur qui se trouve sur la machine client. Enfin, lenavigateurafficheces résultats sur l’écrande l’utilisateur.LaFigure 17.2illustrel’architecturedecetypedesystème.
FIGURE17.2Systèmed’accèsàunebasededonnéessurleWebdotéed’une
extensionserveur.
LesextensionsclientCertes, les navigateurs Web sont conçus et optimisés pour être facilesd’emploi et pour se connecter à toutes sortes de sites Web. Mais les
navigateurslesplusrépandus(MicrosoftInternetExplorer,MozillaFirefoxou encore Apple Safari) n’ont été ni conçus ni optimisés pour servird’interfaceàdesbasesdedonnées.PourmanipulerunebasededonnéesviaInternet,leclientabesoind’unefonctionnalitéquelenavigateurnefournitpas.Pourpallierceproblème,différents typesd’extensionsclient ont étédéveloppés. Ces extensions sont soit des applications dites d’assistance(helper), soit des contrôlesActiveX, soit des applettes Java, soit encoredesscripts.Généralement,lesextensionscommuniquentavecleserveurviaHTML, le principal langage du Web. Un code HTML qui a besoind’accéderàunebasededonnéesesttraduitparl’extensionserveurenSQLcompatibleODBCavantd’êtretransmisàlasourcededonnées.
LescontrôlesActiveXLescontrôlesActiveXdeMicrosoftfonctionnentavecInternetExplorer,detrèsloinleplusrépandudesnavigateursWeb(quoiqueChromeetMozillaFirefoxcommencentàluifaireunpeud’ombre).
LesscriptsLesscriptssontlesoutilslesplussouplespourcréerdesextensionsclient.L’emploi d’un langage de scripts, comme le polyvalent JavaScript ouVBScriptdeMicrosoft,vouspermetdecontrôlertrèsprécisémentcequisepassecôtéclient.Vouspouvezmettreenplacedesvalidationsdeschampsde saisie, cequipermetde rejeteroucorrigerdesdonnéeserronées sansavoiràlestransmettresurleWeb.Celapeutvousfairegagnerdutempstouten diminuant le trafic sur le Web, ce dont les autres utilisateurs vousremercieront.À l’instar des applettes Java, les scripts sont intégrés dansdes pages HTML et s’exécutent lorsque l’utilisateur interagit avec cespages.
ODBCsurunintranetUnintranetestunréseaulocalouétenduquifonctionneexactementcommeune version simplifiée d’Internet. Comme un intranet se limite à uneorganisation, vous n’avez pas besoin demettre en place des systèmes desécurité élaborés tels que des pare-feu. Tous les outils conçus pour ledéveloppementd’applicationssurleWebpermettentégalementdecréerdesapplicationspourunintranet.
ODBC fonctionnede lamêmemanière surun intranet que sur Internet.Sivous gérez plusieurs sources de données, les clients qui utilisent desnavigateursWebainsiquelesextensionsappropriéespeuventcommuniqueraveccessourcesviaducodeSQLquitraverselesétagesHTMLetODBCdelafusée.Auniveaudupilote,leSQLcompatibleODBCesttraduitdanslelangagedecommandesnatifdelabasededonnées,puisexécuté.
JDBCJDBC(JavaDataBaseConnectivity,connectivitéauxbasesdedonnéespourJava) ressemblebeaucoup àODBC,mais il endiffère sur certainspointsimportants.CommeODBC,JDBCestuneinterfacedebasesdedonnéesquiseprésentetoujoursdelamêmemanièreàunprogrammeclient,etcequellequesoitlasourceaveclaquelleils’interface.Commelelaisseentendresonnom, une des divergences de fond avecODBC est que JDBC fonctionneuniquement avec des applications écrites en Java et non en C++ ou enVisualBasic.UneautredifférenceestqueJDBCetJavaont tousdeuxétéconçusdèsledépartpourfonctionnersurleWebousurunintranet.
Java est un langage qui ressemble au C++. Il a été conçu par SunMicrosystemsdanslebutspécifiquededévelopperdesprogrammesclientpourleWeb.Unefoislaconnexionétablieentreunserveuretunclientviale Web, l’applette Java appropriée est téléchargée sur le poste client, àpartirdequoiellecommenceàs’exécuter.L’applette,quiestintégréedansunepageHTML,fournitauclient lesfonctionnalitésdont ilabesoinpouraccéder aux données hébergées sur le serveur. La Figure 17.3 est unereprésentation schématique d’une application de base de données pour leWebutilisantuneappletteJavaexécutéesurlamachineclient.
Uneappletteestunepetiteapplicationquirésidesurunserveur.Lorsqu’unclient se connecte à ce serveur via leWeb, l’applette est téléchargée etcommence son exécution sur l’ordinateur client. Les applettes Java sontspécifiquement conçues pour fonctionner dans un bac à sable. Un bac àsableestunezonedemémoireparfaitementdélimitéesurl’ordinateurclientet dans laquelle l’applette peut s’exécuter. Elle n’est pas autorisée àdéborder de son bac à sable personnel, ce qui permet de protéger lamachine client d’applettes hostiles qui tenteraient de lui soustraire desinformationssensiblesoudel’endommager.
FIGURE17.3ApplicationdebasededonnéespourleWebutilisantuneappletteJava.
Undesprincipauxavantagesapportésparl’utilisationdesapplettesJavaestqu’elles sont systématiquement à jour. En effet, elles sont téléchargéesdepuisleserveurlorsdechaqueutilisation(etnonconservéessurlepostedu client), si bien que le client dispose toujours de la dernière versiond’uneapplette.
Si vous êtes responsable de la maintenance d’un serveur, vous n’avezjamais besoin de vous soucier des questions de compatibilité avec vosclients lorsquevousmettez à jour le logiciel du serveur. Il vous suffit devérifierquel’appletteJavatéléchargeableestcompatibleaveclanouvelleconfiguration du serveur. Si leurs navigateurs Web sont correctementconfigurés pour exécuter des applettes Java, tous vos clients resterontautomatiquement et parfaitement compatibles. Java est un langage deprogrammation complet qui permet d’écrire des applications robustesservant à accéder à des bases de données sur toutes sortes de systèmesclient/serveur.Ainsiutilisée,uneapplicationJavaquiaccèdeàunebasededonnéesvia JDBCest semblableàuneapplicationC++quiaccèdeàunebasededonnéesviaODBC.Parcontre, lesdifférencesdefonctionnement
apparaissent dès lors qu’il est uniquement question d’Internet (ou d’unintranet).
Si le système auquel vous comptez accéder se trouve sur Internet, lesconditions de travail ne sont plus du tout les mêmes que sur un systèmeclient/serveur.Lapartieclientd’uneapplicationquifonctionnesurInternetest un navigateur dont les capacités de traitement sont très réduites. Cescapacités doivent être étendues pour pouvoir accéder à une base dedonnées.C’estcequepermettentlesapplettesJava.
Ilesttoujoursrisquédetéléchargerquoiquecesoitsurunserveurquin’estpastotalementdignedeconfiance.Lerisqueestminimedanslecasd’uneappletteJava,maisiln’estpascomplètementéliminé.Faitestrèsattentionavant d’installer du code exécutable sur votremachine lorsqu’il provientd’unserveurpotentiellementsuspect.
CommeODBC,JDBCtransmetàlasourcededonnéesquisetrouvesurleback end les instructions SQL provenant de l’application front end(l’applette).Iltransmetégalementlesrésultatsetlesmessagesd’erreurdelasourcededonnéesvers l’application.Tout l’intérêtd’utiliserJDBCestqueledéveloppeurd’uneapplettepeutécriresonprogrammeens’appuyantsurl’interfacestandardJDBC,sansavoiràtenircomptedelanaturedelabase de données située sur le back end. JDBC effectue toutes lesconversionsrequisespourassurerunecommunicationbidirectionnelleentreleclientetlasourcededonnées.
À
Chapitre18SQLetdonnéesXML
DANSCECHAPITRE:
» UtiliserSQLavecXML.
» XML,basesdedonnéesetl’Internet.
partirdeSQL:2008,lestandardSQLdel’ISO/IECsupporteXML.LesfichiersXML (eXtensibleMarkup Language) sont rapidement devenusun standard universellement accepté pour l’échange de données entre
plates-formesdifférentes.AvecXML,iln’estplusimportantdesavoirsilapersonne avec laquelle vous échangez des données a ou non unenvironnement différent, un système d’exploitation différent ou même unmatériel différent. XML est le pont qui vous permet d’échanger desdonnées.
LiensentreSQLetXMLCommeHTML,XMLestunlangagedebalises.Autrementdit,cen’estpasunlangagecomplet,àl’instarduC++oudeJava.Ilnes’agitmêmepasd’unsous-langage, comme SQL. Par contre, à l’inverse des autres, il«comprend»lecontenudesdonnéesqu’il transporte.HTMLnes’occupequeduformatagedutexteetdesgraphismes.XMLnes’ensouciepas.Pourgérer lamise en forme d’un document, il faut lui associer une feuille destyle(HTMLutilisantd’ailleursluiaussicetteméthode).
Lastructured’undocumentXMLestdécriteparsonschémaXML,exempledemétadonnées (données qui décrivent des données). Un schéma XMLdécritoùlesélémentssetrouventdansundocumentetdansquelordreilspeuventapparaître.Ilpeutaussidécrireletypededonnéesd’unélémentetcontraindrelesvaleursquecetypepeutrecouvrir.
SQLetXMLfournissentdeuxmanièresdifférentespermettantdestructurerdes données afin de les enregistrer et d’y retrouver les informationsvoulues:
» SQLestunexcellentoutilpourgérerdesdonnées
numériquesettextuellespouvantêtregroupéespartypeet
possédantunelongueurdéfinie.
SQLaétécréédanslebutdestandardiserletraitementet
lagestiond’informationsprésentesdansunebasede
donnéesrelationnelle.
» XMLestmeilleurpourtravaillersurdesdonnéesdontla
formen’estpasprédéfinieetquinepeuventêtre
facilementrangéesdansdescatégoriesprécises.
CequiamotivélacréationdeXML,c’estessentiellementle
besoindeposséderunstandarduniverselpourletransfert
dedonnéesentreplates-formesdifférentesetpour
l’affichagesurleWorldWideWeb.
Les forces et les faiblesses de SQL et de XML sont complémentaires.Chacunrègneenmaîtresursonpropredomaineetformedesalliancesavecl’autre afindedonner auxutilisateurs les informationsqui les intéressent,quandilsleveulentetlàoùilsleveulent.
LetypededonnéeXMLLe type XML a été introduit dans SQL:2003. Cela signifie que lesimplémentations conformes au standard peuvent directement enregistrer ettraiterdesdonnéesauformatXML,sansqu’ilsoitbesoindelesconvertiraupréalabledansl’undestypesdeSQL.
Le type XML, y compris ses sous-types, fonctionne comme un type dedonnée défini par l’utilisateur (tout en étant intrinsèque à chaqueimplémentation).Lessous-typessont:
» XML(DOCUMENT(UNTYPED))
» XML(DOCUMENT(ANY))
» XML(DOCUMENT(XMLSCHEMA))
» XML(CONTENT(UNTYPED))
» XML(CONTENT(ANY))
» XML(CONTENT(XMLSCHEMA))
» XML(SEQUENCE)
Le type XML met SQL et XML en contact étroit, car il permet auxapplications d’effectuer des opérations SQL sur du contenu XML, et àl’inversedesopérationsXMLsurducontenuSQL.Vouspouvezinclureunecolonne du type XML au milieu de colonnes possédant l’un des typesdécrits dans le Chapitre 2 dans une jointure. Avec une base de donnéesvéritablement relationnelle, votre SGBDdéterminera lamanière optimaled’exécuterlarequête.
QuandutiliserletypeXMLDécider si vous devriez ou non enregistrer des données au format XMLdépenddel’usagequevouscomptezenfaire.Voiciquelquescirconstancesdanslesquellescettetechniquepeutêtreintéressante:
» Lorsquevousvoulezenregistrerunblocentierde
données,puisleretrouverplustard.
» Lorsquevousvoulezpouvoirinterrogerl’ensembledu
documentXML.Certainesimplémentationsontétendula
portéedel’opérateurEXTRACTpourpermettrel’extraction
ducontenudésirédansundocumentXML.
» Lorsquevousavezbesoind’untypagefortdedonnées
dansdesinstructionsSQL.EnutilisantletypeXML,vous
êtescertainquevousdisposezdevaleursvalides,etpas
simplementdechaînesdecaractèresarbitraires.
» Lorsquevousvoulezassurerlacompatibilitéavecde
futurs(etdoncpasencoredéfinis)systèmesdestockage
quipourraientnepassupporterdestypesactuels,telsque
CHARACTERLARGEOBJECT,ouCLOB(voyezleChapitre2
pourplusd’informationssurcetobjet).
» Sivousvoulezprofiterdefuturesoptimisationsquine
supporterontplusqueletypeXML.
VoiciunexemplemontrantcommentvouspourriezutiliserletypeXML:
CREATETABLECLIENTS(
NOM_CLIENTCHARACTER(30)NOTNULL,
ADRESSE_1CHARACTER(30),
ADRESSE_2CHARACTER(30),
VILLECHARACTER(25),
ETATCHARACTER(2),
CODE_POSTALCHARACTER(10),
TELEPHONECHARACTER(13),
FAXCHARACTER(13),
CONTACTCHARACTER(30),
CommentairesXML(SEQUENCE));
L’instructionSQLquisuitvaenregistrerundocumentXMLdanslacolonneCommentaires de la table CLIENT. Le document résultant pourraitressembleràceci:
<Comments>S
<Comment>
<CommentNo>1</CommentNo>
<MessageText>Est-cequeVetLabest
équipépour
analyser
dusangdepingouin?</MessageText>
<ResponseRequested>Oui</ResponseRequested>
</Comment>
<Comment>
<CommentNo>2</CommentNo>
<MessageText>Mercipourlacéléritéde
l’envoi
desrésultats
Concernantleprélèvementdephoque
gris</Mes-
sageText>
<ResponseRequested>Non</ResponseRequested>
</Comment>
</Comments>
QuandnepasutiliserletypeXMLCen’estpasparcequeSQL:2003vouspermetd’utiliserletypeXMLquevous devez toujours le faire. En fait, cela n’amême aucun sens dans denombreusescirconstances.Laplupartdesdonnéesdesbasesrelationnellesactuelles ont un format qui leur convient parfaitement. Voici quelquesexemplesdecasdanslesquelsletypeXMLn’aaucuneutilité:
» Lorsquelesdonnéessedécomposentnaturellementen
unestructurerelationnelle,avecdestables,desligneset
descolonnes.
» Lorsquevousavezbesoindemettreàjourdespartiesd’un
documentetnonpasdetraiterglobalementcedocument.
AssocierSQLetXML,XMLetSQL
PouréchangerdesdonnéesentredesbasesSQLetdesdocumentsXML,ilfautquelesdiversélémentsdelabasepuissentêtretranscritsenélémentséquivalents du document XML. Et réciproquement. Dans les sections quisuivent,j’expliquequelsélémentsontbesoind’êtreconvertis.
JeuxdecaractèresEnSQL,lesupportdesjeuxdecaractèresdépenddevotreimplémentation.Cela signifie que DB2 (IBM) peut supporter des jeux de caractères queMicrosoftSQLServern’acceptepas.Demême,SQLServerpeutsupporterdes jeux de caractères qui ne le sont pas parOracle.Certes, les jeux decaractères les plus courants sont universellement reconnus.Mais, dans lecasdebesoinsspécifiques,migrerunebasededonnéesetsesapplicationsd’unSGBDàunautrepeutêtredifficile.
XMLneconnaîtpascesproblèmesdecompatibilité. Ilneseserteneffetqued’unseuljeudecaractères:Unicode.Dupointdevuedel’échangededonnéesentreXMLetuneimplémentationSQLquelconque,c’estunebonnenouvelle.Tous lesvendeursdeSGBDdoiventdéfinirunecorrespondancebidirectionnelleentre leschaînesdechacunde leurs jeuxdecaractèresetUnicode.Letravails’arrêtelà,précisémentpuisqueXMLn’accepteaucunautre jeu de caractères. Sinon, le problème deviendrait beaucoup pluscomplexe.
IdentificateursXML est plus strict que SQL quant aux caractères autorisés dans lesidentificateurs. Les signes légaux dans SQL, mais illégaux pour XML,doivent être transformés en quelque chose d’acceptable avant de pouvoirêtre utilisés dans un document XML. SQL supporte des identificateursdélimités. Cela signifie que toutes sortes de caractères bizarroïdes,comme %, $ et &, sont légaux dès lors qu’ils sont placés entre desguillemets.DupointdevuedeXML,detelssignessontillégaux.Deplus,lesnomsXMLquicommencentparXML(quellequesoitlacombinaisondemajusculesetdeminuscules)sontdesmotsréservés,etdoncnepeuventpasêtreemployésentouteimpunité.
Si, par le plus grand des hasards, vous avez utilisé ces lettres au débutd’identificateursSQL,vousdevrezchangerleursnoms.
CertainesrèglespermettentdecréerunpontentreSQLetXML.EnpassantàXML,touslesidentificateursSQLsontconvertisenUnicode.Àpartirdelà, ceuxqui sont aussi légauxpourXMLdemeurent inchangés.Les autressontremplacésparuncodehexadécimalprenantpourforme«_xNNNN_»ou « xNNNNNNNN_ », où N représente un chiffre hexadécimal enmajuscule. Par exemple, le trait de soulignement (_) sera représenté par« _x005F_ ». De même, « _x003A_ » correspond à la virgule. Lesvaleurs hexadécimales précédentes sont précisément les codes du trait desoulignement et de la virgule en Unicode. Le cas d’identificateurs SQLdébutant par les caractères x, m et l est réglé en préfixant ce genred’instanceparuncodedelaforme«xFFFF».
Les conversions sontplus simplesdans l’autre sens (deXMLversSQL).Toutcequ’ilyaàfaireestdescannerlescaractèresd’unnomXMLpourychercherlaprésenced’uneséquence«xNNNN_»ou«_xNNNNNNNN».IlsuffitalorsdelaremplacerparlecaractèreUnicodecorrespondant.SiunnomXMLdébuteparlaséquence«xFFFF_»,elledoitsimplementêtreignorée.
Ensuivantcesquelquesrègles,vouspouvezconvertirunidentificateurSQLen un nom XML, puis revenir à un identificateur SQL. Par contre, lasituationestmoinsconfortablequandils’agitdeconvertirunnomXMLenidentificateurSQLetretour.
TypesdedonnéesLestandardSQLspécifiequ’untypededonnéeSQLdoitêtreconvertidansletypeXMLSchemaleplusprochepossible.L’expression«leplusprochepossible » signifie que toutes les valeurs autorisées par le type SQL leseront aussi par le typeXML Schema, et qu’unminimum de valeurs nonpermises par le type SQL sera autorisé par le type XML Schema. Danscertainscas,ilestpossiblederéduirel’étenduedesvaleursXMLàlaplageautoriséepar le typeSQLcorrespondant.PrenonsparexempleunevaleurSQLdetypeINTEGER.Elleappartientàl’intervallefermé-2157483648,2157483647. Sous XML, la valeur maxInclusive peut être définiecommeétant égale à2157483647, et lavaleurminInclusive commeétant égale à - 2157483648.Voici un exemplemettant enœuvre une tellecorrespondance:
<xsd:simpleType>
<xsd:restrictionbase=»xsd:integer>
<xsd:maxInclusivevaleur=»2157483647»/>
<xsd:minInclusivevaleur=»-2157483648»/>
<xsd:annotation>
<sqlxml:sqltypename=»INTEGER»/>
</xsd:annotation>
</xsd:restriction>
</xsd:simpleType>
La sectionannotation contient des informations sur la définition dutypeSQL.Ellen’estpasutiliséeparXML,maisellepeutêtreintéressantesiledocumentestreconvertiplustardversSQL.
TablesVouspouvezassocierune tableàundocumentXML.Celavautégalementpour toutes les tables d’un schéma ou d’un catalogue. Cette opérationconserve les privilèges. Une personne possédant un privilège SELECTrestreint à certaines colonnes d’une table ne pourra associer que cescolonnes au document XML. La procédure produit en réalité deuxdocuments : l’uncontient lesdonnéesde la table, l’autre le schémaXMLqui décrit le premier document.Voici par exemple cequepeut donner cegenred’opération:
<CLIENTS>
<row>
<PRENOM>Abe</PRENOM>
<NOM>Abelson</NOM>
<VILLE>Springfield</VILLE>
<CODE>714</CODE>
<TELEPHONE>555-1111</TELEPHONE>
</row>
<row>
<PRENOM>Bill</PRENOM>
<NOM>Bailey</NOM>
<VILLE>Decatur</VILLE>
<CODE>714</CODE>
<TELEPHONE>555-2222</TELEPHONE>
</row>
.
.
.
</CLIENTS>
L’élément racine du document a pris le nomde la table.Chaque ligne decelle-ciestcontenuedansunélément<row>.Cetélémentdécritunesuitedecolonnesprovenantdelatableetportantlemêmenomquedanscelle-ci.Enfin,chaqueélémentdecolonnecontientunevaleurdedonnée.
GérerlesvaleursnullesLes données SQL peuvent être nulles (vides, non définies ou encoreindéterminées).VousdevezdéciderdelafaçondelesreprésenterdansundocumentXML.Vousdisposezpourceladedeuxoptions:nilouabsent.Sivous choisissez la méthode nil, l’attribut xsi : nil= » true »marque les élémentsde colonnesdont lavaleurdans la table est nulle. Ilpeutêtreutilisédelamanièresuivante:
<row>
<PRENOM>Abe</PRENOM>
<NOM>Abelson</NOM>
<VILLExsi:nil=»true»/>
<CODE>714</CODE>
<TELEPHONE>555-1111</TELEPHONE>
</row>
L’optionabsentpourraitêtreimplémentéeainsi:
<row>
<PRENOM>Abe</PRENOM>
<NOM>Abelson</NOM>
<CODE>714</CODE>
<TELEPHONE>555-1111</TELEPHONE>
</row>
Danscecas,lalignecontenantlavaleurnulleesttoutsimplementomise.
GénérerleschémaXMLDans une association entre SQL etXML, le premier document généré estcelui qui contient les données. Le second concerne les informations deschéma. À titre d’exemple, considérons le schéma pour le documentCLIENTSutiliséplushautdanslasection«Tables»:
<xsd:schema>
<xsd:simpleTypename=»CHAR_15»>
<xsd:restrictionbase=»xsd:string»>
<xsd:lengthvalue=«15»/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleTypename=»CHAR_25»>
<xsd:restrictionbase=»xsd:string»>
<xsd:lengthvalue=«25»/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleTypename=»CHAR_3»>
<xsd:restrictionbase=»xsd:string»>
<xsd:lengthvalue=«3»/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleTypename=»CHAR_8»>
<xsd:restrictionbase=»xsd:string»>
<xsd:lengthvalue=«8»/>
</xsd:restriction>
</xsd:simpleType>
<xsd:sequence>
<xsd:elementname=»PRENOM»
type=»CHAR_15»/>
<xsd:elementname=»NOM»type=»CHAR_25»
/>
<xsd:elementname=»VILLE»
type=»CHAR_25»nil-
lable=»true»/>
<xsd:elementname=»CODE»type=»CHAR_3»
nil-
lable=»true»/>
<xsd:elementname=»TELEPHONE»
type=»CHAR_8»
nillable=»true»/>
</xsd:sequence>
</xsd:schema>
Ceschémaestappropriésil’approchenilestutiliséepourgérerlesvaleursSQL nulles. L’approche absent impose une définition des élémentslégèrementdifférente.Parexemple:
<xsd:elementname=»VILLE»type=»CHAR_25»
minOccurs=»0»/>
FonctionsSQLopérantsurdesdonnéesXML
Le standard SQL définit une série d’opérateurs, fonctions etpseudo-fonctionsquiproduisentunrésultatXMLquandonlesappliqueàune base de données SQL, ou qui à l’inverse produisent un résultat auformatSQLstandardlorsqu’onlesappliqueàdesdonnéesXML.Dansles
sectionsquisuivent, jedonneunebrèvedescriptiondesfonctionslespluscourantes que sont XMLELEMENT, XMLFOREST, XMLCONCAT etXMLAGG, ainsi quedeplusieurs autresqui sont fréquemment employéespour publier sur le Web. Certaines d’entre elles reposent fortement surXQuery,unnouveaulangagederequêtestandardspécifiquementconçupourinterroger des donnéesXML.XQuery est en lui-mêmeun vaste sujet, quidépasseévidemmentlecadredecelivre.
XMLDOCUMENTL’opérateurXMLDOCUMENTprendunevaleurXMLenentréeet retourneune autre valeur XML en sortie. La nouvelle valeur XML est un nœuddocument construit selon les règles du constructeur d’un document dansXQuery.
XMLELEMENTL’opérateurXMLELEMENT traduit unevaleur relationnelle enun élémentXML.Vouspouvezl’utiliserdansuneinstructionSELECTpourmettredesdonnéesprovenantdelabaseSQLauformatXMLenvuedelespubliersurleWeb.Parexemple:
SELECTc.NOM
XMLELEMENT(NAME«VILLE»,c.VILLE)AS«Resultat»
FROMCLIENTSc
WHERENOM=»Abelson»;
Voicilerésultatrenvoyé:
Nom Résultat
Abelson <VILLE>Springfield</VILLE>
XMLFOREST
L’opérateurXMLFORESTproduit une liste, ou forêt, d’éléments XML àpartirdevaleursrelationnelles.Chacunedesvaleursdel’opérateurgénèreunnouvelélément.Envoiciunexemple:
SELECTc.NOM
XMLFOREST(c.VILLE,
c.CODE,
c.TELEPHONE)AS«Resultat»
FROMCLIENTSc
WHERENOM=«Abelson»ORNOM=«Bailey»;
Cefragmentdecodedonneralasortiesuivante:
Nom Résultat
Abelson <VILLE>Springfield</VILLE><CODE>714</CODE>
<TELEPHONE>555-1111</TELEPHONE>
Bailey <VILLE>Decatur</VILLE>
<CODE>714</CODE>
<TELEPHONE>555-2222</TELEPHONE>
XMLCONCATXMLCONCAT représente une autre manière de produire une forêtd’éléments en concaténant ses arguments XML. Par exemple, le code ci-dessous:
SELECTc.NOM
XMLCONCAT(
XMLELEMENT(NOM«prenom»,c.PRENOM)
XMLELEMENT(NOM«nom»,c.NOM)
)AS«Resultat»
FROMCLIENTSc;
produitcesrésultats:
Nom RésultatAbelson <prenom>Abe</prenom>
<nom>Abelson</nom>
Bailey <prenom>Bill</prenom>
<nom>Bailey</nom>
XMLAGGLa fonction d’agrégation XMLAGG prend des documents XML (ou desfragments de documents) et produit un nouveau document unique commesortied’unerequêteGROUPBY.L’agrégationcontientuneforêtd’éléments.Voyonsunexemplequiillustrececoncept:
SELECTXMLELEMENT
(NAME«Ville»
XMLATTRIBUTES(c.VILLEAS«name»)
XMLAGG(XMLELEMENT(NAME«nom»c.NOM
))
)AS«ListeVilles»
FROMCLIENTSc
GROUPBYVILLE;
Lorsqu’elleestexécutéesurnotre tableCLIENTS,cette requête fournit lerésultatsuivant:
ListeVilles
<Villename=»Decatur»>
<nom>Bailey</nom>
</Ville>
<Villename=»Philo»>
<nom>Stetson</nom>
<nom>Stetson</nom>
<nom>Wood</nom>
</Ville>
<Villename=»Springfield»>
<nom>Abelson</nom>
</Ville>
XMLCOMMENTLa fonction XMLCOMMENT permet à une application de créer uncommentaireXML.Sasyntaxeestlasuivante:
SXMLCOMMENT(‘contenuducommentaire’
[RETURNING
{CONTENT|SEQUENCE}])
Parexemple:
XMLCOMMENT(‘Sauvegarderlabasetouslesjoursà
2hdu
matin.)
créeuncommentaireXMLsemblableàcelui-ci:
<!--Sauvegarderlabasetouslesjoursà2hdu
matin.-->
XMLPARSELafonctionXMLPARSEproduitunevaleurXMLeneffectuantuneanalysesansvalidationd’unechaîne.Vouspourriezl’utiliserdecettemanière:
XMLPARSE(DOCUMENT‘Beautravail!‘
PRESERVEWHITESPACE)
Le code ci-dessus renverrait une valeur XML du typeXML (UNTYPEDDOCUMENT) ou XML (DOCUMENT). Le sous-type choisi dépend del’implémentationquevousutilisez.
XMLPILa fonctionXMLPIpermet aux applications de créer des instructions detraitementXML.Sasyntaxeseprésenteainsi:
XMLPINAMEcible
[,expression-chaîne]
[RETURNING
{CONTENT|SEQUENCE}])
Le container cible désigne l’identificateur de la cible visée parl’instructiondetraitement.expression-chaînereprésentelecontenudecetteinstruction.CettefonctioncréeuncommentaireXMLdelaforme:
<?cibleexpression-chaîne?>
XMLQUERYLa fonction XMLQUERY évalue une expression XQuery et renvoie lerésultatdelarequêteàl’applicationSQL.LasyntaxedeXMLQUERYestlasuivante:
XMLQUERY(expression-XQuery
[PASSING{BYREF|BYVALUE}
liste-arguments]
[RETURNING{CONTENT|SEQUENCE}
{BYREF|BYVALUE})
Voiciunexempled’utilisationdeXMLQUERY:
SELECTmoyenne_max,
XMLQUERY(
‘for$moyenne_batteurin
/joueur/moyenne_batteur
where/joueur/nom=$var1
return$moyenne_batteur’
PASSINGBYVALUE
‘Mantle’ASvar1
RETURNINGSEQUENCEBYVALUE)
FROMstats_attaque;
XMLCASTLa fonction XMLCAST est semblable au CAST de SQL, mais avecquelques restrictions supplémentaires. Elle permet à une application depratiquer le transtypage d’une valeur d’un type XML vers un autre typeXMLou vers un typeSQL.Elle peut aussi servir dans l’autre sens, pourtransformeruntypeSQLenuntypeXML.Maisilyaquelquescontraintesàrespecter:
» Aumoinsundestypesinvoqués(lasourceoula
destination)doitêtreuntypeXML.
» LestypesSQLinvoquésnepeuventêtreniunecollection,
niuneligne,niuntypestructuré,niuneréférence.
» Seuleslesvaleurspossédantl’undestypesXMLouletype
SQLnulpeuventêtretransforméesenXML(UNTYPED
DOCUMENT)ouXML(DOCUMENT).
Voiciunexemple:
XMLCAST(CLIENTS.NomClientASXML(UNTYPED
DOCUMENT)
La fonction XMLCAST est transformée en un CAST SQL ordinaire. Laseuleraisonquijustifiel’emploid’unmotclédifférentest lanécessitéderespecterlescontraintesci-dessus.
Prédicats
Unprédicatrenvoieunevaleurvraie(True)oufausse(False).Denouveauxprédicatsontétéajoutéspourlesbesoinsdel’interconnexionentreSQLetXML.
DOCUMENTL’objetduprédicatDOCUMENTestdedéterminersiunevaleurXMLestundocument.IltestecettevaleurpourvérifiersielleestuneinstancedutypeXML (UNTYPED DOCUMENT) ou XML (ALL DOCUMENT). Sasyntaxeestlasuivante:
XML-valeurIS[NOT]
[ANY|UNTYPED]DOCUMENT
Si l’expression est évaluée comme étant vraie, le prédicat retourne True.Sinon, il renvoie False. Si la valeur XML est nulle, le prédicat retourneUNKNOWN. Si ANY ou UNTYPED ne sont pas spécifiés, le prédicatsupposepardéfautqu’ils’agitd’ANY.
CONTENTLe prédicat CONTENT sert à déterminer si une valeur XML est uneinstancedeXML(ANYCONTENT)ouXML(UNTYPEDCONTENT).Envoicilasyntaxe:
XML-valeurIS[NOT]
[ANY|UNTYPED]CONTENT
SiANYouUNTYPEDnesontpasspécifiés,leprédicatsupposepardéfautqu’ils’agitd’ANY.
XMLEXISTSComme son nom l’indique, le prédicat XMLEXISTS a pour but dedéterminersiunevaleurexiste.Sasyntaxeseprésenteainsi:
XMLEXISTS(expression-XQuery
[liste-arguments])
L’expression XQuery utilise les valeurs fournies dans la liste desarguments. Si cette expression renvoie une valeur SQL nulle, le résultatfourniparleprédicatestUNKNOWN.Sil’évaluationretourneuneséquenceXQuery vide, le prédicat vaut FALSE. Sinon, il est vrai (TRUE). CeprédicatpeutserviràdéterminersiundocumentXMLcontientuncontenuspécifiqueavantd’utiliserunepartiedececontenudansuneexpression.
VALIDLeprédicatVALIDapourbutd’évaluerunevaleurXMLafindevoirsielleestvalidedanslecontexted’unschémaXMLenregistré.Sasyntaxeestpluscomplexequecelledesautresprédicats:
XML-valeurIS[NOT]VALID
[XMLoptiondecontrainted’identitévalide]
[XMLclausedecorrespondancevalide]
Leprédicat contrôle si lavaleurpossèdebien l’undescinq typesXML :XML (SEQUENCE), XML (ANY CONTENT), XML (UNTYPED
CONTENT),XML(ANYDOCUMENT),XML(UNTYPEDDOCUMENT).Deplus, il peut vérifier demanière facultative si la validité de la valeurXML s’appuie sur des contraintes d’identité, et si cette validité estconformeàunschémaXMLparticulier.
Lecomposantoptiondecontrainted’identitéoffrequatrepossibilités:
» WITHOUTIDENTITYCONSTRAINTS:C’estlasupposition
quiestfaitepardéfautsiaucuneautreoptiondecontrainte
d’identitén’estutilisée.SiDOCUMENTestspécifié,elle
fonctionnecommeunecombinaisondesprédicats
DOCUMENTetVALIDWITHIDENTITYCONSTRAINTS
GLOBAL.
» WITHIDENTITYCONSTRAINTSGLOBAL:Cecomposant
demandeàvérifierlaconformitédelavaleuravecle
schémaXMLainsiqu’aveclesrèglesXMLpourlesrelations
ID/IDREF.
IDetIDREFsontdestypesd’attributsXMLquiidentifientles
élémentsd’undocument.
» WITHIDENTITYCONSTRAINTSLOCAL:Cecomposant
demandeàvérifierlaconformitédelavaleuravecle
schémaXML,maispasaveclesrèglesXMLpourles
relationsID/IDREFoulesrèglesduschémaXMLpourles
contraintesd’identité.
» DOCUMENT:Cecomposantsignifiequelavaleurestun
documentetqu’ellerespectelemodeWITHIDENTITY
CONSTRAINTSGLOBALavecuneclausede
correspondancevalide.Celle-ciidentifieleschémapour
lequellavaleurdoitêtrevalidée.
TransformerdesdonnéesXMLentablesSQL
Jusqu’àunepérioderécente,laréflexionsurlesrelationsentreSQLetXMLtournaient essentiellement autour de la question suivante : « Commentconvertir des données d’une table SQL au format XML pour les rendreaccessibles sur l’Internet ? » Les plus récents ajouts au standard SQLtraitentaussiduproblèmeinverse:«CommentconvertirdesdonnéesXMLentablesSQLpourpouvoirlesinterrogerfacilementàl’aided’instructionsSQLstandard?»
Lapseudo-fonctionXMLTABLEestchargéed’effectuercetteopération.Sasyntaxeestlasuivante:
XMLTABLE([déclaration-espace-noms,]
expression-XQuery
[PASSINGliste-arguments]
COLUMNSdéfinitions-colonnes-tableXML
oùlalisted’argumentsseprésenteainsi:
expression-valeurASidentificateur
Tandis que définitions-colonnes-tableXML est une liste dedéfinitionsdecolonnesséparéesparunevirguleetquipeutcontenir:
nom-colonneFORORDINALITY
et/ou:
nom-colonnetype-donnée
[BYREF|BYVALUE]
[clause-par-défaut]
[PATHexpression-XQuery]
Voici un exemple vous montrant comment il est possible d’utiliserXMLTABLEpourextrairedesdonnéesd’undocumentXMLetlesenvoyerversunepseudo-tableSQL.Une telle table auneduréedevie éphémère,mais elle se comporte pour le reste comme une table SQL tout à faitnormale.Sivousvoulezque lesdonnéessoientpermanentes,vouspouvezfaire appel à une instructionCREATETABLE puis insérer les donnéesXMLdanslatablenouvellementcréée:
SELECTtelephoneclient.*
FROM
clients_xml,
XMLTABLE(
‘for$min
ol/client
return
$m’
PASSINGclients_xml.clientAS«col»
COLUMNS
«Nom_Client»CHARACTER(30)PATH
‘Nom_Client’,
«Telephone»CHARACTER(13)PATH
‘Telephone’
)AStelephoneclient;
L’exécutiondecetteinstructionfourniraunrésultatdecestyle:
Nom_ClientTelephone
AbeAbelson(714)555-1111
BillBailey(714)555-2222
ChuckWood(714)555-3333
TypesdedonnéesnonprédéfinisetXML
DanslestandardSQL,lestypesdedonnéesnonprédéfiniscomprennentlesdomaines, les types utilisateurs distincts, les tableaux et les multisets(ensembles multiples). Vous pouvez tous les transformer en donnéesformatéespourXMLenutilisant lecodeapproprié.Lesquelquessectionsquisuiventvousproposentdesexemplessimples.
DomainePour convertir un domaine SQL vers XML, vous devez tout d’aborddisposerd’undomaine.Pourcetexemple,nousallonsencréerungrâceàl’instructionCREATEDOMAIN:
CREATEDOMAINCoteOuestASCHAR(2)
CHECK(EtatIN(‘CA’,‘OR’,‘WA’,‘AK’));
Définissonsmaintenantunetablequiutilisecedomaine:
CREATETABLERegionOuest(
NomClientCharacter(20)NOTNULL,
EtatCoteOuestNOTNULL
);
VoicileschémaXMLpermettantdetranscrirenotredomaineenXML:
<xsd:simpleType>
Name=‘DOMAIN.Ventes.RegionOuest’>
<xsd:annotation>
<xsd:appinfo>
<sqlxml:sqltypekind=‘DOMAIN’
schemaName=‘Ventes’
typeName=‘CoteOuest’
mappedType=‘CHAR_2’
final=‘true/>
</xsd:appinfo>
</xsd:annotation>
<xsd:restrictionbase=‘CHAR_2’/>
</xsd:simpleType>
Lorsque ce mappage est appliqué, il en résulte un document XML quicontientquelquechosecomme:
<RegionOuest>
<row>
.
.
.
<Etat>AK</Etat>
.
.
.
</row>
.
.
.
</RegionOuest>
Typedéfiniparl’utilisateurdistinctLetravailestàpeuprèslemêmequepourundomaine,ainsiquelemontrel’exemplesuivant:
CREATETYPECoteOuestASCHARACTER(2)FINAL;
VoicileschémaXMLpermettantdetranscrirenotretypeenXML:
<xsd:simpleType>
Name=‘UDT.Ventes.RegionOuest’>
<xsd:annotation>
<xsd:appinfo>
<sqlxml:sqltypekind=‘DISTINCT’
schemaName=‘Ventes’
typeName=‘CoteOuest’
mappedType=‘CHAR_2’
final=‘true’/>
</xsd:appinfo>
</xsd:annotation>
<xsd:restrictionbase=‘CHAR_2’/>
</xsd:simpleType>
Ilcréeunélémentidentiqueàceluiobtenuavecledomaineprécédent.
LigneLe type ROW vous permet de récupérer d’un coup l’ensemble desinformations d’une ligne dans un seul champ. Vous pouvez créer un typeROWdansunedéfinitiondetableenprocédantcommesuit:
CREATETABLEInfoContact(
NomCharacter(30),
TelephoneROW(MaisonCHAR(13),TravailCHAR
(13))
);
Ilestmaintenantpossibled’effectuerunmappagedecetypeversXMLavecleschémasuivant:
<xsd:complexTypeName=‘ROW.1’>
<xsd:annotation>
<xsd:appinfo>
<sqlxml:sqltypekind=‘ROW’
<sqlxml:fieldname=‘Maison’
mappedType=
‘CHAR_13’/>
<sqlxml:fieldname=
‘Travail’
mappedType=
‘CHAR_13’/>
</sqlxml:sqltype>
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
<xsd:elementName=‘Maison’nillable=
‘true’
Type=‘CHAR_13’/>
<xsd:elementName=‘Travail’nillable=
‘true’
Type=‘CHAR_13’/>
</xsd:sequence>
</xsd:complexType>
CeschémapourraitgénérerlaséquenceXMLsuivantepourunecolonne:
<Telephone>
<Maison>(888)555-1111</Maison>
<Travail>(888)555-1111</Travail>
</Telephone>
TableauIlestpossibledeplacerplusieursélémentsdansunseulchampenutilisantle type ARRAY à la place de ROW. Reprenons l’exemple de la tableInfoContact en déclarant la colonneTELEPHONE comme étant untableau:
CREATETABLEInfoContact(
NomCharacter(30),
TelephoneCharacter(13)ARRAY[4]
);
Ilestmaintenantpossibled’effectuerunmappagedecetypeversXMLavecleschémasuivant:
<xsd:complexTypeName=‘ARRAY_4.CHAR_13’>
<xsd:annotation>
<xsd:appinfo>
<sqlxml:sqltypekind=
‘ARRAY’
maxElements=‘4’
mappedElementType=
‘CHAR_13’
/>
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
<xsd:elementName=‘element’
minOccurs=‘0’maxOccurs=‘4’
nillable=‘true’Type=‘CHAR_13’/>
</xsd:sequence>
</xsd:complexType>
Ceschémagénéreraitquelquechosecomme:
<Telephone>
<element>(888)555-1111</element>
<element>xsi:nil=‘true’/>
<element>(888)555-3434</element>
</Telephone>
L’élémentdutableauquicontientxsi:nil=‘true’reflète le faitque lesecondnumérode téléphonecontientunevaleurnulledans la tablesource.
MultisetLes numéros de téléphone de l’exemple précédent pourraient êtreenregistrésdansunmultiset(unensemblemultiple)àlaplaced’untableau.Ladéfinitiondenotretableseprésenteraitalorsainsi:
CREATETABLEInfoContact(
NomCharacter(30),
TelephoneCharacter(13)MULTISET
);
Ilestmaintenantpossibled’effectuerunmappagedecetypeversXMLavecleschémasuivant:
<xsd:complexTypeName=‘MULTISET.CHAR_13’>
<xsd:annotation>
<xsd:appinfo>
<sqlxml:sqltypekind=
‘MULTISET’
mappedElementType=
‘CHAR_13’
/>
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
<xsd:elementName=‘element’
minOccurs=‘0’maxOccurs=‘unbounded’
nillable=‘true’Type=‘CHAR_13’/>
</xsd:sequence>
</xsd:complexType>
Ceschémagénéreraitquelquechosecommececi:
<Telephone>
<element>(888)555-1111</element>
<element>xsi:nil=‘true’/>
<element>(888)555-3434</element>
</Telephone>
LemariagedeSQLetdeXML
SQLfournituneméthodestandarduniversellepourlestockagededonnéesd’unemanière hautement structurée. La structure permet à l’utilisateur degérerdesdonnéesdetypeetdetailletrèsdifférents,ainsiqued’extrairedecesbanquesdedonnéeslesinformationsdontilabesoin.XMLestdevenuun standard officiel pour le transport de données entre plates-formesincompatibles,enparticuliersurl’Internet.Enassociantcesdeuxméthodes,leurvaleurindividuelles’entrouvedémultipliée.
Sommaire
Couverture
SQLPochePourlesNuls,3e
Copyright
Introduction
Ausujetdecelivre
Quidevraitlirecelivre?
Icônesutiliséesdanscelivre
Pourcommencer
I.DébuterenSQL
Chapitre1-Lesbasesdedonnéesrelationnelles
Conserverlatracedeschoses
Qu’est-cequ’unebasededonnées?
Volumeetcomplexitéd’unebasededonnées
Qu’est-cequ’unsystèmedegestiondebasesdedonnées?
Lesfichierspleintexte
Lesmodèlesdebasededonnées
Chapitre2-LesbasesdeSQL
CequeSQLn’estpas
Un(tout)petitpeud’histoire
LescommandesSQL
Lesmotsréservés
Lestypesdedonnées
Lesvaleursnulles
Lescontraintes
UtiliserSQLsurunsystèmeclient/serveur
UtiliserSQLsurl’Internetouunintranet
Chapitre3-LescomposantsdeSQL
Lelangagededéfinitiondedonnées(DDL)
Lelangagedecontrôlededonnées(DCL)
II.UtiliserSQLpourcréerdesbasesdedonnées
Chapitre4-Créeretmaintenirunesimplestructuredebasededonnées
CréerunesimplebasededonnéesenutilisantunoutilRAD
CréerunetableavecleDDLdeSQL
Delaportabilité
Chapitre5-Créerunebasededonnéesrelationnellemultitable
Concevoirlabasededonnées
Travailleravecdesindex
Maintenirl’intégrité
Normaliserlabasededonnées
III.Enregistreretextrairedesdonnées
Chapitre6-Manipulerlesdonnéesd’unebase
Extrairedesdonnées
Créerdesvues
Modifierlesvues
Ajouterdenouvellesdonnées
Modifierdesdonnéesexistantes
Transférerdesdonnées
Supprimerdesdonnéesobsolètes
Chapitre7-Gérerl’historiquedesdonnées
ComprendrelespériodesdansSQL:2011
Travailleravecdestablesdepériodesdetemps-application
Travailleravecdestablesdeversionssystèmes
Tracerencorepluslesdonnéesavecdestablesbitemporelles
Chapitre8-Spécifierdesvaleurs
Valeurs
Lesexpressionsdevaleur
Lesfonctions
Chapitre9-ExpressionsSQLavancées
LesexpressionsconditionnellesCASE
Conversionsdetypesdedonnées(CAST)
Lesexpressionsvaleurdeligne
Chapitre10-Isolerlesdonnéesdontvousavezbesoin
Clausesmodificatrices
ClausesFROM
LesclausesWHERE
Connecteurslogiques
LeslimitesdeFetch
Regarderparunefenêtrepourcréerunjeuderésultats
Chapitre11-Lesopérateursrelationnels
UNION
INTERSECT
EXCEPT
LesopérateursJOIN
ONetWHERE
Chapitre12-Effectuerdesrecherchesapprofondiesavecdesrequêtesimbriquées
Quefaitunesous-requête?
Chapitre13-Requêtesrécursives
Qu’est-cequelarécursivité?
Qu’est-cequ’unerequêterécursive?
Quandutiliserunerequêterécursive?
Àquoid’autrepeutmeservirunerequêterécursive?
IV.Contrôlerlesopérations
Chapitre14-Protégerunebasededonnées
LelangagedecontrôlededonnéesdeSQL(DCL)
Lesniveauxd’accèsdel’utilisateur
Accorderdesprivilègesauxutilisateurs
Accorderdesprivilègesentreniveaux
Donnerlepouvoird’accorderdesprivilèges
Retirerdesprivilèges
UtilisersimultanémentGRANTetREVOKEpourgagnerdutempsetdesefforts
Chapitre15-Protectiondesdonnées
Menacessurl’intégritédesdonnées
Réduirelerisquedecorruptiondesdonnées
Contraintesettransactions
Chapitre16-UtiliserSQLdansdesapplications
SQLdansuneapplication
UtiliserSQLdansdeslangagesprocéduraux
V.UtiliserSQLdanslemonderéel
Chapitre17-ODBCetJDBC
ODBC
ODBCsurunintranet
JDBC
Chapitre18-SQLetdonnéesXML
LiensentreSQLetXML
LetypededonnéeXML
AssocierSQLetXML,XMLetSQL
FonctionsSQLopérantsurdesdonnéesXML
Prédicats
TransformerdesdonnéesXMLentablesSQL
TypesdedonnéesnonprédéfinisetXML
LemariagedeSQLetdeXML