Create table
CrĂ©er une table consiste de lâexpression create table
suivi par le nom de la table et ensuite, entre parenthĂšses, la liste dâattributs et leurs contraintes.
En créant nos tables, on essaie au maximum d'assurer les domaines exprimés dans notre schéma avec un objectif ultime : assurer l'intégrité de nos données !
On ne veut pas de valeurs non valides dans la base
On veut forcer la présence de certaines valeurs, ou savoir explicitement quand il y a des valeurs manquantes
On veut forcer l'unicité de certaines valeurs
Quand il y a un lien entre deux tables, il faut que ce lien soit assuré et qu'il n'est pas cassable par erreur !
On assure l'intégrité de nos données via les contraintes.
Intégrité : Contrainte par type de données
Nous imposons une premiÚre contrainte sur le type de chaque attribut (ou colonne) de notre table. Cette contrainte est la premiÚre façon d'implémenter la contrainte sur le domaine des valeurs possibles pour un attribut.
char(n)
Une chaĂźne de caractĂšres de longueur fixe. char(8) stockera toujours 8 caractĂšres, mĂȘme si la valeur quâon passe en a moins (des espaces seront ajoutĂ©s Ă la fin).
varchar(n)
Une chaĂźne de caractĂšres de longueur variable.
text
Une longue chaßne de caractÚres plus adaptés aux paragraphes etc.
int
Valeurs entiĂšres
numeric(p,d)
Valeurs avec un point décimal fixe : p digits en total, avec d digits aprÚs le point. Ex. numeric(3,2) peut stocker la valeur 2.45 mais pas 24.45
real
Valeurs dĂ©cimales avec la prĂ©cision dĂ©pendant de lâarchitecture de la machine
double
Valeurs dĂ©cimales avec double prĂ©cision dĂ©pendant de lâarchitecture de la machine
float(n)
Une valeur décimale avec une précision de n digits.
boolean
Une binaire
date
Une date
datetime
Une date et heure
Testons notre table, en ajoutant quelques lignes, avec la commande insert into
:
La commande insert into
a la syntaxe suivant :
On nâest pas obligĂ© dâinclure tous les attributs dâune table :
Soit une valeur default
est inséré à la place de l'attribut, manquant, soit NULL
:
45
Gone with the wind
5.99
66
Les bronzés font du ski
NULL
Exercice
Ăcrivez et testez la crĂ©ation dâune table pour votre entitĂ© Repas de lâexercice prĂ©cĂ©dente.
Vous utilisez quel type de donnĂ©e pour stocker les textes Ă©crit par lâutilisateur ?
Vous utilisez quel type de donnée pour stocker une image ?
Testez lâinsertion de quelques donnĂ©es.
Intégrité : Contraintes sur le contenu des colonnes
Par dĂ©faut, chaque attribut autorise les valeurs nulles. On peut encore limite les domaines d'une colonne en enlevant la possibilitĂ© des nulles, prĂ©ciser lâunicitĂ© des valeurs sur la table entiĂšre, ou bien contraindre les valeurs possibles via une condition.
Il y a plusieurs sortes de contraintes sur les colonnes :
not null
: les valeurs nulles ne sont pas autoriséesunique
: les valeurs doivent ĂȘtre uniques sur toutes les lignes de la tablecheck
: valider une donnée selon un critÚre
Il existe aussi un opérateur default
qui permet de fluidifier la contrainte not null
, en fournissant une valeur par défaut dans l'absence d'une vraie valeur.
L'exemple suivant démontre les différentes contraintes, ainsi que l'utilisation de default
(ici, c'est une table pour la gestion des colis Ă livrer) :
null
vs not null
vs default
Attention au piĂšge de default
! On risque de changer le sens d'un attribut en fournissant une valeur default
:
Est-ce qu'il faut ĂȘtre averti de l'absence d'une information pendant la saisie ? Si oui, il faut utiliser
not null
seul (sansdefault
). Le SGBDR va lancer une exception, et aucune information inconsistante sera conservée.Est-ce qu'il faut savoir explicitement quand il a l'absence d'une information ? Si oui, il faut autoriser les
null
(sansdefault
). On peut ensuite extraire des lignes avec des infos manquantes avec une phraseselect
et la conditionis null
, par exemple.
En revanche, si on précise default
dans le deux cas dessus, on risque de ne pas savoir si une information a été manquante ou pas, ni extraire des lignes qui manquent une information. On ne peut pas distinguer entre une valeur précisée par default
d'une valeur saisie par l'utilisateur.
Exercice
Copiez et exécutez la DDL de cette table « package »
Essayez des instructions de type « INSERT »
Sans « name », sans « price » ?
Avec article_count = 0, < 0 ?
Sans date_of_creation ? Est-ce que CHECK suffit Ă la place de NOT NULL ?
Intégrité : Contraintes par la clé primaire
Nous savons déjà qu'une clé primaire s'agit de notre choix de clé parmi les clés candidates de notre entité. Cette clé doit avoir la caractéristique de pouvoir identifier une ligne unique parmi toutes les lignes de la table.
Désignant une clé primaire, alors, impose implicitement plusieurs contraintes d'intégrité sur la ou les colonnes de la clé :
unique : les valeurs dans les attributs de la clĂ© primaire doivent ĂȘtre uniques sur toute la table
not null : les valeurs ne peuvent pas ĂȘtre nulls
indexation : un index est construit sur ces attributs (notamment pour garantir l'unicité)
Testons ces rÚgles avec notre table film, en essayant d'ajouter une ligne sans préciser la clé primaire :
Nous avons imposé une contrainte type primary key
sur la colonne film_id, sans spécifier de valeur default
. Nous aurons donc l'erreur affichée.
Rappelez, une clé candidate peut se composer de plusieurs attributs, et donc en SQL, il est possible de créer une clé primaire composée :
Exercice
Essayez d'ajouter plusieurs combinaisons de lignes Ă film_actor
Avec des valeurs
null
Avec 2 fois le mĂȘme film_id, mais des actor_id diffĂ©rents
Avec 2 fois le mĂȘme film_id et actor_id
Intégrité référentielle
En normalisation notre schéma, nous avons dû couper nos entités en deux.
Les lignes avec un lien sémantique sont reliées par une ou plusieurs colonnes, qu'on appelle les clés étrangÚres.
Rappelez l'exemple de la table etudiant_cours et la table cours :
1
SGBDR
1
Backend
2
Angular
3
Backend
3
Angular
SGBDR
1000
Backend
1500
Angular
2000
Ici, l'attribut cours_id de la table etudiant_cours est une clé étrangÚre, car il pointe vers la ligne correspondante dans la table cours.
Ce lien est maintenu strictement par notre SGBDR :
on ne peut pas supprimer le cours Angular, par exemple, car la suppression créera une incohérence dans nos données. Que deviennent des étudiants qui à priori sont inscrits du cours Angular, alors que le cours Angular n'existe plus ?
on ne peut pas ajouter des Ă©tudiants qui prennent des cours qui ne se trouvent pas dans la table cours. Nous limitons le domaine possible via cette contrainte.
Cette protection implicite dans notre SGBDR s'appelle l'intégrité référentielle.
Mais, cela n'est pas automatique. Nous sommes obligés d'exprimer les clés étrangÚres manuellement :
Nous avons ajouté la clause foreign key...
:
Exercice
Insérez des données dans cours
Essayer dâinsĂ©rer des lignes dans etudiant_cours
Avec des noms des cours existants
Avec des noms des cours qui nâexistent pas
Essayez de supprimer une ligne de cours avec la ligne suivante :
Si pas déjà fait, insérer un cours avec un cours_id de "SGBDR". Ajouter un étudiant à ce cours, en créant une ligne dans etudiant_cours.
Essayez de modifier le nom du cours "SGBDR" Ă "DBMS". Qu'est-ce qu'il se passe ?
L'intégrité référentielle est toujours assurée par le SGBDR !
Nous n'avons pas à faire de pre-tests ou de pre-vérifications de la validité des données. Notre SGBDR s'en occupe tout seul !
Cascades
Il existe des scĂ©narios dans lesquels la modification ou suppression dâune ligne dâune table parent devrait faire modifier/supprimer les lignes dans les tables enfants.
Pour continuer notre exemple, la personne qui a saisi le nouveau cours a fait une faute de frappe, et on a déjà des étudiants inscrits à ce cours. Comment corriger la faute si le SGBDR n'autorise pas la modification ?
Par défaut, notre SGBDR impose des contraintes les plus fortes sur nos références par clé étrangÚre :
pas de suppression
pas de mise Ă jour
Nous pouvons modifier ce comportement pour ĂȘtre plus souple, en prĂ©cisant ce qu'il faut faire dans le cas d'une suppression ou modification d'une rĂ©fĂ©rence par clĂ© Ă©trangĂšre.
Ici, nous spécifions que faire dans le cas d'une suppression ou modification. Il y a trois possibilités :
cascade
: faire une sorte de propager nos modifications dans les autres tables liées par la clé-étrangÚre. Par exemple, toutes les lignes dans etudiant_cours avec "SGBDR" seront modifiés à "DBMS".set null
: Nous cassons les liens existants entre les deux tables, en mettantnull
dans la clé étrangÚre (seulement si autorisé)set default
: Affecter une valeur par défaut (en cassant aussi les liens)
Si on oublie de préciser les rÚgles on delete
ou on update
à la création initiale, il est bien possible de les ajouter plus tard. Nous serions obligés de supprimer la clé étrangÚre, et ensuite la recréer.
Chaque clé (primaire ou étrangÚre) crée implicitement une contrainte dans notre SGBDR, qui lui dispose d'un identifiant. On peut récupérer toutes ses meta-données de nos tables avec la commande suivante :
Le résultat retourné est :
On voit dans le résultat la ligne :
C'est la ligne qui met en place la contrainte par clé étrangÚre. Pour la modifier :
Exercice
Ajoutez les options de cascade sur la clé étrangÚre sur etudiant_cours.
En utilisant
update
, mettez Ă jour le nom de SGBDR Ă DBMS. Quâest-ce qui se passe ?En utilisant
delete
, essayez de supprimer la ligne SGBDR. Quâest-ce qui se passe ?
Intégrité vs Cascades vs Null vs Default
Les cascades sont trĂšs pratiques pour assurer de lâintĂ©gritĂ© automatique sur plusieurs tables. MAIS... le choix nâest pas facile !
Sâil est important de garder un historique, les cascades ne sont pas nĂ©cessairement utiles :
un Ă©tudiant sâinscrit Ă un cours et il y participe. On facture sa participation au cours. LâĂ©tudiant quitte lâĂ©cole. Il faut quand mĂȘme le facturer le temps passĂ© au cours⊠si on avait fait un
ON DELETE CASCADE
on nâaurait plus de trace de sa participation, et donc une facturation erronĂ©e
Pour des données « temps réels » les cascades sont trÚs utiles
un Ă©tudiant sâinscrit Ă un cours et il y participe. Il faut gĂ©nĂ©rer la feuille dâĂ©margement LâĂ©tudiant quitte lâĂ©cole. On ne veut plus voir lâĂ©tudiant sur la feuille dâĂ©margement, donc un
ON DELETE CASCADE
serait pratique dans ce cas.
Comment anticiper ces deux scenarii ? Une bonne analyse du domaine (il aura fallu identifier le cas de départ d'un étudiant, ainsi que la cas de facturation prorata), le suivi des procédures de normalisation, etc.
DerniĂšre mise Ă jour