2. Bases de données, schémas et tables

Les notions de bases de données et de schémas sont malheureusement rendues assez confuses par les éditeurs, qui leur ont donné des applications différentes. Sous Oracle, une instance de serveur gère une base de données, divisées en schémas et espaces de tables. Un utilisateur Oracle se connecte au serveur, et le serveur le place dans son schéma par défaut, en général partagé avec d'autres utilisateurs. Sous MySQL, une instance de serveur gère autant de bases de données que l'on souhaite. La notion de sous-espace de tables n'existe pas. Un utilisateur MySQL se connecte au serveur, qui le place dans sa base de données, éventuellement partagée avec d'autres utilisateurs. On voit que dans le premier cas, l'espace de travail s'appelle schéma , et dans le second base de données . Cette différence, qui prête à confusion, ne change en fait pas grand chose pour l'utilisateur non administrateur : il travaille dans un espace, éventuellement avec d'autres, sans se préoccuper de la machinerie qui se trouve à l'extérieur de son espace. Une table est une structure dans laquelle on peut enregistrer des données. Une table est un ensemble de lignes, chaque ligne est un ensemble de colonnes. À chaque colonne est associée un type de donnée : entier, chaîne de caractères, date ou type binaire. Une table peut comporter zéro ligne, en revanche elle doit toujours comporter au moins une colonne pour exister.

2.1. Création d'une table

La création d'une table se fait par l'appel à la commande create table. Cette commande est complexe, aussi nous allons découper les arguments qu'elle peut prendre en plusieurs parties. Le premier argument que prend cette commande est le nom de la table, qui doit être unique au sein d'un espace de travail. Le deuxième argument que prend cette commande est composé de deux parties :
  • une liste de colonnes, qui doit comporter au moins une colonne ;
  • une liste de contraintes sur cette table, éventuellement vide.
Voici un exemple simple d'une création de table, avec une unique colonne, et aucune contrainte sur la table.

Exemple 18. Une table à une colonne sans contrainte

create  table (
   id  int
) ;

Examinons dès maintenant la façon de déclarer les colonnes, nous reviendrons ensuite sur les contraintes de table.

2.2. Création d'une colonne

La déclaration d'une colonne est elle-même une déclaration complexe. Elle se compose de trois éléments :
  • le nom de la colonne, qui doit être unique au sein de sa table ;
  • le type de la colonne ;
  • les contraintes sur cette colonne.

2.2.1. Nom de la colonne

Un nom de colonne est une chaîne de caractères classique. En théorie, on peut utiliser des caractères accentués pour créer des colonnes, et mélanger les majuscules / minuscules. En pratique, les problèmes de compatibilité que cela peut poser, entre autres entre les environnements Windows et Linux, rendent ce genre de pratique dangereuses.

2.2.2. Type d'une colonne

MySQL définit une trentaine de types différents pour une colonne, qui se regroupent en quatre familles :
  • les chaînes de caractères, de longueur fixe ou variable ;
  • les nombres, dont la précision peut être fixée ;
  • les dates ;
  • les types binaires, de tailles variables.
On détaillera ces différents éléments au chapitre Type de données.

2.2.3. Contraintes sur une colonne

Il y a sept contraintes sur les colonnes disponibles en SQL :
  • La contrainte de clé primaire : primary key. Toute table d'une base de données se doit de posséder une clé primaire, même si cela n'est pas obligatoire. Il ne peut y avoir qu'une seule colonne portant la contrainte primary key, bien qu'il soit possible de regrouper plusieurs colonnes dans la déclaration d'une clé primaire. Cette contrainte implique deux choses pour les valeurs de cette colonne : il ne peut pas y avoir de valeur nulle, et il ne peut y avoir de doublons.
  • La contrainte de clé étrangère : foreign key references. Cette contrainte prend un paramètre de type table(colonne), qui désigne quelle colonne de quelle table est référencée par cette colonne. On appelle cette contrainte une contrainte d'intégrité référentielle . Souvent la colonne référencée par la clé étrangère est elle-même clé primaire dans sa table, mais ce n'est pas une obligation.
  • La contrainte null ou not null. Cette contrainte impose que les valeurs portées par cette colonne peuvent être nulles, ou au contraire ne doivent pas être nulles. Comme par défaut les valeus portées par une colonne peuvent être nulles, il est assez rare de rencontrer la contrainte null. En revanche, la seconde contrainte est très fréquente.
  • La contrainte unique indique que les doublons ne sont pas acceptés dans cette colonne.
  • La contrainte default. Cette contrainte prend un paramètre, qui indique la valeur par défaut des cellules de cette colonne. Cette valeur est donc utilisée dans tous les cas où la valeur de cette cellule n'est pas précisée lors de la création d'une ligne.
  • La contrainte check. Cette contrainte est très puissante et permet de valider les valeurs insérées.
  • La contrainte collate. Cette contrainte est utilisée sur les colonnes qui portent des chaînes de caractères, et indique comment ces chaînes doivent être comparées les unes avec les autres. La collation de chaînes de caractères représente l'action de les comparer ou de les trier. Ce problème est très simple lorsque l'on se limite aux lettres minuscules non accentuées, et peut devenir rapidement très complexe lorsque l'on prend en compte les accents (aussi appelés diacritiques) et les différences minuscules / majuscules. L'utilisation de cette contrainte permet d'indiquer quelles méthodes de comparaison vont être utilisées. Nous n'irons pas plus loin sur ce point.

2.3. Contraintes sur une table

Il existe quatre types de contrainte sur une table :
  • La contrainte primary key. Cette contrainte prend en paramètre une liste de colonnes, et indique que la combinaison des valeurs doit constituer une clé primaire pour la ligne considérée.
  • La contrainte foreign key : indique que le groupe de colonnes en paramètres référence le groupe de colonne en paramètre du references qui doit suivre. Les colonnes ou groupe de colonnes référencées ne sont pas obligatoirement des clés primaires, la seule contrainte nécessaire sur elle est unique.
  • La contrainte unique. Cette contrainte prend en paramètre une liste de colonnes, et indique que la combinaison des valeurs de ces colonnes pour une ligne donnée doit être unique.
  • La contrainte check : indique un certain nombre de règles qui doivent être vérifiées sur un groupe de colonnes.

2.4. Nommage des contraintes

Enfin notons qu'il est possible de nommer toutes les contraintes que l'on définit. Si l'on ne donne pas de nom explicite à ces contraintes, alors elles porteront des noms par défaut. Ces noms sont utilisés par les systèmes de base de données dans leurs messages d'erreur, il est donc parfois très utile de donner des noms explicites à ces contraintes, de façon à pouvoir s'y référencer rapidement. Nous verrons plusieurs exemples de nommages de contraintes dans les exemples qui suivent.

2.5. Exemples de création de tables

Voyons à présent des exemples utilisant toutes ces définitions.

Exemple 19. Table avec clé primaire et nom unique

create  table country (
   id    int  primary  key, 

   name  varchar(32)  unique  not  null
) ;

Cette première table permet d'enregistrer des pays. Chaque pays possède un ID, qui constitue sa clé primaire. Il est décrit par un nom, qui doit être unique, et non nul.

Exemple 20. Table avec clé primaire composite, étrangère, contrainte check

create  table team (
   country_id  int  not  null  references country(id) , 
   id  int  not  null, 
    
   name  varchar(32)  unique  not  null, 

    constraint pk_team  primary  key (id, country_id)
) ;

Notre deuxième table permet de stocker des équipes. Chaque équipe appartient à un pays, représenté par la colonne country_id, déclaré comme clé étrangère sur la colonne id de la table country. Il possède une déclaration de contrainte sur une table : une clé primaire composite, sur les colonnes id et country_id. Une clé primaire déclarée sur plusieurs colonnes est appelée clé primaire composite .

Exemple 21. Table avec contrainte check complexe

create  table player (
   country_id           int  not  null  references country(id) , 
   id                   int  not  null, 

   team_id              int  references team(id), 

   family_name  varchar(32)  not  null, 
   first_name   varchar(32)  not  null, 

   retired              int  not  null  default 0  check (retired = 1  or retired = 0),

   birth_year           int  not  null  check (birth_year > 0), 
   prof_year            int  not  null  check (prof_year > birth_year), 

    constraint pk_player  primary  key (id, country_id)
) ;

Le même mécanisme de clé primaire composite, et de clé étrangère est utilisé pour créer cette table player. Notons qu'un joueur peut appartenir à une équipe, mais que cette équipe ne fait pas partie de la clé primaire. Effectivement, un joueur en inter-contrat ne fait partie d'aucune équipe, donc ce champ doit pouvoir être nul, il ne peut donc pas participer à la clé primaire. De plus, ce champ verra certainement sa valeur varier, et ce n'est jamais une bonne idée de faire varier la clé primaire d'une entité. Enfin, notons la déclaration de la contrainte sur la valeur retired, qui prend la valeur 0 par défaut, et ne peut prendre que les valeurs 1 ou 0.

2.6. Modification d'une table

Il est possible de modifier certaines caractéristiques d'une table une fois qu'elle a été créée. La commande que l'on utilise pour ce faire est alter table suivi du nom de la table. Notons enfin que certaines opérations peuvent être assez délicates. Par exemple, ajouter une colonne à une table qui contient des lignes remplira cette colonne automatiquement avec des valeurs nulles. Si cette colonne doit finalement porter la restriction not null, les choses doivent être faites en plusieurs étapes.

2.6.1. Ajout d'une colonne

L'ajout d'une colonne utilise la même syntaxe que la création d'une colonne dans une table. Simplement la commande de création proprement dite se place après le alter table. Dans l'exemple suivant on ajoute une colonne capital_name à notre table country.

Exemple 22. Ajout d'une colonne à la table country

alter  table country
    add  column capital_name  varchar(32) ;

2.6.2. Ajout d'une contrainte

Ajouter une contrainte suit également la même syntaxe que la création d'une contrainte sur une table. Dans l'exemple suivant, on ajoute une contrainte permettant de garantir l'unicité du couple formé du nom du pays et du nom de sa capitale.

Exemple 23. Ajout d'une contrainte

alter  table country
    add  constraint unique_name_capital  unique(name, capital_name) ;

Un exemple très fréquemment rencontré est l'ajout de contrainte de type clé étrangère d'une table vers une autre. Effectivement, de telles contraintes nécessitent que la table cible existe avant la création de cette contrainte. Dans le cas de contraintes circulaires, cette condition ne peut pas être remplie, ce qui arrive fréquemment. L'approche utilisée classiquement consiste donc à créer les tables dans un premier temps, puis les contraintes de type clé étrangère une fois qu'elles sont toutes créées. C'est en particulier l'approche utilisée par tous les outils de mapping objet / relationnel.

Exemple 24. Ajout d'une contrainte de type clé étrangère

alter  table player
    add  constraint FK_player_team  foreign  key(team_id) 
    references team(id) ;

2.6.3. Cas particulier de not null

Dans MySQL, il n'est pas possible de modifier la contrainte not null à l'aide de la commande alter table ... add constraint. Ajouter cette contrainte se fait à l'aide de la syntaxe suivante.

Exemple 25. Ajout d'une contrainte not null

alter  table country
   modify  column id  int  not  null ;

L'une des conséquences est que cette contrainte ne peut pas être nommée. On remarquera qu'il faut préciser à nouveau le type de données portée par cette colonne.

2.6.4. Suppression d'une colonne

La suppression d'une colonne doit être faite avec précaution. Effectivement, une colonne peut être référencée par de nombreux éléments SQL : des contraintes de table, des clés étrangères, des index ou des vues. Dans tous ces cas, il faut analyser tous ces éléments, et éventuellement les modifier avant de procéder à cette suppression. L'exemple suivant montre la suppression de la colonne capital_name de notre table country.

Exemple 26. Suppression d'une colonne

alter  table country
    drop  column capital_name ;

Si l'on suit les exemples de ce chapitre sous MySQL, on se rendra compte que la contrainte unique_name_capital existe toujours, mais qu'elle ne référence plus la colonne que l'on vient de supprimer.

2.6.5. Suppression d'une contrainte

La suppression d'une contrainte se fait en utilisant le nom de cette contrainte. Si l'on a pris garde de nommer explicitement toutes ses contraintes cela ne posera donc pas de problème, sinon il faut interroger la base afin de trouver le nom attribué à la contrainte que l'on souhaite effacer. L'exemple suivant permet d'effacer la contrainte unique_name_capital que nous avons créée sur la table country.

Exemple 27. Effacement d'une contrainte

-- version SQL standard
 alter  table country
    drop  constraint unique_name_capital ;

 -- version MySQL
 alter  table country
    drop  index unique_name_capital ;

On remarquera une différence de syntaxe entre le SQL standard et la commande MySQL.

2.7. Effacement d'une table

La commande pour effacer une table est drop. Pour effacer la table player il suffit donc de taper le code suivant.

Exemple 28. Effacement de la table player

drop  table player ;

2.8. Remarques sur restrict et cascade

Ces deux mots-clés, ajoutés à la commande de création d'une clé étrangère, permettent de préciser le comportement du système lorsqu'une ligne référencée par cette clé est effacée ou mise à jour. En mode restrict, l'effacement est interdit, en mode cascade, il se propage. Dans le cas de notre exemple de clé entre la table Marins et la table Communes, on ne pourra effacer une commune référencée si la clé étrangère a été déclarée en mode restrict, en revanche, tous les marins nés dans cette commune seront effacés si la clé a été déclarée en mode cascade.

Exemple 29. Déclaration d'une clé étrangère en mode restrict

alter  table marins
    add  constraint  foreign  key FK_communes (id_commune) 
                   references communes(id)  on  delete  restrict ;

Le mode restrict ou cascade peut être déclaré sur les opérations de délétion ( delete) et de mise à jour ( update).
Introduction à SQL
Retour au blog Java le soir
Cours & Tutoriaux
Table des matières
Introduction
1. Un peu d'histoire
2. Organisation de la présentation
Un premier exemple
1. Un premier exemple
1.1. Construction d'une première table
1.2. Enregistrer quelques données
1.3. Extraire des données
2. Trier, classer, calculer
2.1. Classer des données
2.2. Trier des données
2.3. Effectuer des calculs
2.4. Mise à jour d'une valeur
3. Sélection sur plusieurs tables
3.1. Ajout du lieu de naissance
3.2. Clés primaires et clés étrangères
Organisation des données
1. Introduction
2. Bases de données, schémas et tables
2.1. Création d'une table
2.2. Création d'une colonne
2.3. Contraintes sur une table
2.4. Nommage des contraintes
2.5. Exemples de création de tables
2.6. Modification d'une table
2.7. Effacement d'une table
2.8. Remarques sur restrict et cascade
3. Types de données
3.1. Les types numériques
3.2. Les types caractère
3.3. Les types temporels
3.4. Les types binaires
3.5. Type auto-incrémental de MySQL
3.6. Type auto-généré de Derby
3.7. Séquences d'Oracle
Manipulation des données
1. Introduction
2. Extraire des données : select
2.1. Extraire des données d'une table unique
2.2. Clause where
2.3. Requêtes imbriquées
2.4. Fonctions d'agrégation, groupage
3. Supprimer des données : delete
3.1. Forme générale du delete
3.2. Effacement en cascade
3.3. Fonctionnement du delete
4. Ajouter des données : insert
4.1. Forme générale de l' insert
4.2. Copie d'une table dans une autre
5. Mettre à jour des données : update
5.1. Forme générale de l' update
5.2. Mise à jour avec une requête imbriquée
Interrogations sur plusieurs tables
1. Introduction
2. Formes normales
2.1. Première forme normale
2.2. Deuxième forme normale
2.3. Troisième forme normale
2.4. Formes normales d'ordres supérieurs
3. Relations entre éléments
3.1. Cardinalité d'une relation
3.2. Relation 1:1
3.3. Relation 1:p
3.4. Relation p:1
3.5. Relation n:p
4. Jointures
4.1. Jointure interne
4.2. Jointure externe
4.3. Auto-jointure
5. Unions
6. Vues
6.1. Création d'une vue
6.2. Exemples de vues
Transactions
1. Introduction
2. Isolation des transactions
2.1. ACIDité d'une transaction
2.2. Définition de l'isolation
3. Gestion d'une transaction
3.1. Mode auto-commit
3.2. Fixer le niveau d'isolation
3.3. Démarrer une transaction
3.4. Terminer une transaction
3.5. Remarques importantes
Index
1. Introduction
2. Manipulation d'index
2.1. Création automatique d'index
2.2. Création manuelle d'index