Introduction au langage SQL et Access
Introduction au langage SQL et Access
SQL
SQL a été normalisé par l'ANSI (American National Standards Institute) et par
l'ISO (International Organization for Standardization). Voici les principales étapes de ce
processus :
première norme ANSI en 1986 ;
première norme ISO (SQL1) en 1987, révisée en 1989 ;
deuxième norme ISO (SQL2) en 1992 ;
troisième norme (SQL3) en cours de rédaction depuis 1999 par l'ANSI et l'ISO, après
une très longue gestation, et avec beaucoup de retard sur l'événement.
Bref, il n'y a qu'un seul langage SQL, mais chaque éditeur de SGBD
implémente son propre dialecte. Le "dictionnaire" qui permet de passer d'un dialecte à l'autre
s'appelle ODBC (Open Data Base Connectivity). Il a été imaginé par Microsoft, et mis sur le
marché en 1993.
Contrairement à ce que son nom indique, SQL ne sert pas qu'à écrire des
requêtes. C'est un langage complet, qui permet de créer des BDD, des tables, de saisir des
données et de les corriger, de créer des vues, des index et des états (parfois baptisés
"rapports", par francisation de l'anglais "reports"). Sauf erreur de notre part, il ne permet pas
de créer des formulaires, parce qu'il a été conçu à une époque ou l'interface graphique
n'existait pas sur ordinateur, et parce qu'un formulaire sans interface graphique n'a guère
d'intérêt.
Par contre, dans les SGBD sans interface graphique, le recours à SQL est
obligatoire pour toutes les opérations, y compris la création de la BDD, celle des tables, et la
saisie des données. La tentation est donc forte, pour un professeur qui ignore à quels SGBD
ses étudiants seront confrontés lorsqu'ils entreront dans la vie active, de faire dans son
enseignement une large part à SQL, qui représente l'outil universel de manipulation des
données. Ceci dit, l'interface graphique est tellement entrée dans les moeurs, qu'il parait
difficile qu'à terme tous les SGBD n'en soient pas dotés. En attendant, nous avons adopté une
© TIBB imbwangatroptard@[Link]
2
SQL
position mixte, en commençant par l'interface graphique, plus facile à appréhender, et en
rajoutant à ce tutoriel quatre chapitres consacrés au langage SQL.
Selon notre habitude, nous utiliserons le SGBD Access comme support pratique
de ce tutoriel (ou tutorial, ou cours en ligne). A l'occasion, nous comparerons
l'implémentation du SQL d'Access à celle d'Oracle. Comme nous ne disposons pas d'une base
Oracle (nos moyens ne nous le permettent pas...), nous nous inspirerons d'un manuel de
formation à la version 8 (l'avant-dernière).
3 - La procédure
Pour gérer les tables en langage SQL dans Access, il nous faut opérer de la
manière suivante. Dans la fenêtre "Base de données", nous sélectionnons l'objet
"Requêtes". Nous effectuons un double clic sur "Créer une requête en mode création", nous
refermons la fenêtre "Afficher la table" sans introduire de table et, dans le menu, nous suivons
le chemin suivant :
Requête --> Spécifique SQL --> Définition des données
S'ouvre alors une fenêtre intitulée "Requête1 : Requête Définition des données",
dans laquelle nous pouvons écrire du code SQL.
Pour exécuter ce code, nous cliquons sur l'icône "Exécuter". Pour l'enregistrer,
nous cliquons sur "Enregistrer". Nous constatons alors que le SGBD Access traite notre
code comme une requête.
© TIBB imbwangatroptard@[Link]
3
SQL
Pour modifier le code SQL, nous sélectionnons la requête enregistrée
précédemment, et nous cliquons sur l'icône "Modifier". La fenêtre "Requête Définition des
données" s'ouvre à nouveau.
Tous les exemples cités dans ce chapitre ont été transportés (par copier/coller)
dans Access 2002, et nous avons vérifié leur bon fonctionnement. Vous ne devriez donc pas
rencontrer de difficulté pour les reproduire.
© TIBB imbwangatroptard@[Link]
4
SQL
create table Personnes (Nom char(20),Prénom char(20));
Les conventions relatives aux noms des tables et des champs varient quelque
peu d'un SGBD à l'autre. En ce qui concerne plus particulièrement les champs :
le nombre de
caractères ne doit pas être trop grand (64 dans Access, 18 à 30 dans d'autres SGBD) ;
seuls les lettres, les nombres et le caractère de soulignement sont autorisés. Access
admet les caractères accentués. Il admet aussi l'espace, mais le nom du champ doit alors être
écrit entre crochets ;
certains SGBD requièrent que le nom d'un champ commence par une lettre, mais ce
n'est pas le cas d'Access ;
les termes faisant partie du vocabulaire du langage SQL sont interdits ("date" par
exemple). Ce sont les mots réservés.
Les types de données sont définis dans le DDL (Data Definition Language) de
chaque SGBD, et ils varient beaucoup d'un logiciel à l'autre. Dans Access, les mêmes termes
ne sont pas toujours utilisés dans l'interface graphique, en VBA et en SQL. Voici un
échantillon représentatif des différentes façons d'exprimer un type de données lors de la
création d'une table en SQL dans Access :
Booléen : BIT ;
Nombre entier : SHORT (entier), SMALLINT (entier), LONG (entier long),
INTEGER (entier long), BYTE (octet) ;
Nombre réel : SINGLE (réel simple), DOUBLE (réel double), NUMERIC (réel
double) ;
Monétaire : CURRENCY, MONEY ;
Date/Heure : DATE, TIME, DATETIME ;
Texte : VARCHAR (255 caractères), CHAR(n) ou TEXT(n) (n caractères),
LONGTEXT (mémo, 32K max.) ;
Fichier binaire : LONGBINARY (Objet OLE) ;
Compteur : COUNTER (NuméroAuto).
On notera qu'il n'est pas possible de créer un champ de type hypertexte via une
commande SQL dans Access. Même remarque en ce qui concerne les listes de choix.
Pour supprimer une table, on utilise la clause DROP TABLE, comme le montre
l'exemple suivant :
DROP TABLE Personnes;
© TIBB imbwangatroptard@[Link]
5
SQL
Il est possible de modifier une table existante. Les exemples les plus classiques
concernent l'addition d'une nouvelle colonne et la suppression d'une colonne existante. La
commande :
ALTER TABLE Personnes
ADD Naissance DATE;
La clause INIT, qui permet de donner une valeur initiale aux champs ainsi créés,
ne fonctionne pas dans Access. Par défaut, cette valeur initiale est Null. Pour la modifier, il
faut utiliser une commande UPDATE (dont nous parlerons au paragraphe 9 ci-dessous).
Pour supprimer la colonne que nous venons de créer, nous utilisons la
commande suivante :
ALTER TABLE Personnes
DROP Naissance;
ou sa variante :
ALTER TABLE Personnes
DROP COLUMN Naissance;
En SQL standard, la commande ALTER TABLE peut aussi être utilisée pour
modifier les propriétés d'une colonne existante. Exemple :
ALTER TABLE Personnes
MODIFY Nom CHAR(40);
© TIBB imbwangatroptard@[Link]
6
SQL
Après avoir exécuté la commande nous vérifions, dans le propriétés de la table
"Personnes" ainsi créée, que le Null est interdit dans le champ "Nom".
Pour qu'un champ soit indexé sans doublons, nous utilisons la clause UNIQUE,
comme le montre l'exemple suivant :
CREATE TABLE Personnes
(Nom CHAR(20) UNIQUE,
Prénom CHAR(20));
qui permet d'attribuer le nom "clé_primaire" à la clé ainsi créée. Nous verrons au
paragraphe suivant comment placer une clé sur plusieurs champs.
Les autres clauses permettant de définir les propriétés des champs ne
fonctionnent pas dans Access. Il en est ainsi de DEFAULT, qui permet de fixer la valeur par
défaut d'un champ, ainsi que de CHECK, qui permet de fixer des contraintes sur le contenu
d'un champ (propriété "Valide si").
© TIBB imbwangatroptard@[Link]
7
SQL
Prénom CHAR(20),
CONSTRAINT clé_primaire PRIMARY KEY(Nom));
La création d'un index peut s'effectuer alors que la table existe déjà, mais cela
requiert l'usage d'une syntaxe différente. Créons par exemple un index sur le champ "Nom" de
la table "Personnes" :
CREATE UNIQUE INDEX essai_index
ON Personnes (Nom);
Dans le cas d'un index sur deux champs, cette syntaxe devient :
CREATE UNIQUE INDEX essai_index
ON Personnes (Nom, Prénom);
Mais cette syntaxe standard ne fonctionne pas dans Access. Il faut utiliser la
variante suivante :
DROP INDEX essai_index ON Personnes;
© TIBB imbwangatroptard@[Link]
8
SQL
CREATE TABLE Personnes
(Nom TEXT(30),
Prénom TEXT(30),
Code_Ville LONG);
Dans un troisième temps, nous modifions la table "Villes" en plaçant une clé
primaire sur le champ "Code_Ville", qui servira de côté 1 à la future relation. Pour ce faire,
nous exécutons la commande suivante :
ALTER TABLE Villes
ADD CONSTRAINT clé_primaire PRIMARY KEY(Code_Ville);
Notons que, si nous ne désirons pas donner un nom à la clé (ici "clé_primaire"),
nous pouvons simplifier la commande précédente en l'écrivant ainsi :
ALTER TABLE Villes
ADD PRIMARY KEY(Code_Ville);
Notons que :
si nous ne désirons pas donner un nom à la relation (ici "relation_ville"), et
s'il n'y a pas d'ambiguïté sur le champ qui est du côté 1 de la relation (ici "Code_Ville
de la table "Villes")
Nous vérifions dans la fenêtre "Relations" qu'une relation 1-n a bien été créée
entre les deux tables, avec application de l'intégrité référentielle.
Nous aurions pu être plus directs, en installant les clés (clé primaire et clé
étrangère) dès la création des tables. Pour la table ville, la commande s'écrit :
© TIBB imbwangatroptard@[Link]
9
SQL
CREATE TABLE Villes
(Code_Ville COUNTER PRIMARY KEY,
Ville TEXT(30));
Ces deux commandes étant exécutées, nous vérifions dans la fenêtre "Relations"
que les deux tables sont présentes avec tous leurs champs, et liées par une relation 1-n.
La suppression de cette relation s'obtient à l'aide de la commande ALTER
TABLE. Dans le cas de la table "Personnes", côté n de la relation "relation_ville" créée
précédemment, la commande s'écrit :
ALTER TABLE Personnes
DROP CONSTRAINT relation_ville;
On notera que les options "Mettre à jour en cascade les champs correspondants"
et "Supprimer en cascade les enregistrements correspondants" ne sont pas disponibles.
En conclusion, la création et la suppression d'une relation sont réalisées grâce à
la clause CONSTRAINT appliquée à la table située du côté n de la relation.
Nous vérifions, après exécution de la commande, que Pierre Machin a bien été
introduit dans la table "Personnes". Si nous enregistrons la commande, le SGBD la fait
précéder de l'icône , qui symbolise les requêtes de type "Ajout". Cependant, si nous
essayons de basculer en "Mode création" (le mode graphique), le SGBD Access nous oppose
le message suivant :
En bon français, notre commande ressemble à une requête ajout, elle possède
l'icône d'une requête ajout, elle utilise la clause INSERT comme une requête ajout, mais ce
n'est pas une requête ajout. Qu'on se le dise !
Si le Null n'est pas interdit dans les champs de la table "Personnes", nous
pouvons introduire un nom sans le prénom correspondant, en opérant de la manière suivante :
© TIBB imbwangatroptard@[Link]
10
SQL
INSERT INTO Personnes (Nom)
VALUES
("Truc");
Si nous enregistrons ces deux commandes, le SGBD Access fait précéder leur
nom de l'icône caractéristique des requêtes suppression. Cependant, si nous créons la
requête suppression correspondante en mode graphique, et si nous basculons en mode SQL,
nous obtenons une syntaxe légèrement différente. Nous reviendrons sur ce point au
chapitre 22.
Dans certaines implémentations du langage SQL (mais pas dans Access), on
peut omettre la clause FROM qui suit la clause DELETE.
10 - Conclusion
La création d'une table en SQL n'est pas une travail bien ardu, même s'il est
certain qu'une bonne interface graphique simplifie fortement l'opération. La saisie des
informations en SQL, par contre, est une tâche quasi désespérante. A moins que les données
ne soient importées, l'usage d'une interface graphique s'impose.
En ce qui concerne les tables, l'interface graphique du SGBD Access est
beaucoup plus développée que son interface SQL. Nous verrons dans les chapitres suivants
que la situation est très différente, et nettement plus équilibrée, pour les requêtes.
© TIBB imbwangatroptard@[Link]
11
SQL
Nous avons vu au chapitre précédent qu'il était possible, dans le SGBD Access,
de manipuler les tables en langage SQL. Cependant, les commandes correspondantes sont
considérées comme des requêtes, et il n'est pas possible de basculer entre le mode graphique
et le mode SQL. En effet, le mode graphique s'obtient lorsque l'objet "Tables" est sélectionné,
alors que le mode SQL requiert que l'objet "Requêtes" soit actif.
En ce qui concerne les requêtes, la situation est nettement plus satisfaisante. La
plupart des commandes SQL relatives aux requêtes sont connues du moteur d'Access, et on
bascule sans problème du mode graphique au mode SQL (l'objet "Requêtes" étant
sélectionné).
Il existe cependant quelques exceptions, que nous étudierons au chapitre 21. Il
s'agit des opérations ensemblistes, pour lesquelles il n'existe pas d'interface graphique. Ces
trois opérations sont :
l'union de deux tables, pour laquelle l'opérateur UNION fonctionne ;
l'intersection de deux tables, pour laquelle l'opérateur INTERSECT ne fonctionne
pas ;
la différence de deux tables, pour laquelle les opérateurs EXCEPT et MINUS ne
fonctionnent pas.
Selon notre habitude, nous utiliserons le SGBD Access comme support pratique
de ce tutoriel (ou tutorial, ou cours en ligne).
2 - La sélection simple
Créons, dans l'interface graphique, la requête qui extrait de la table "Personnes"
(contenant une liste de personnes) les deux champs "Nom" et "Prénom". Cliquons sur la petite
flèche située à droite de l'outil "Affichage", et dans la liste déroulante, choisissons
"Mode SQL". La commande (ou instruction) suivante s'affiche :
SELECT [Link], [Link]énom
FROM Personnes;
© TIBB imbwangatroptard@[Link]
12
SQL
sont parfaitement valables. Par prudence, certains professionnels utilisant les
SGBD préfèrent s'abstenir de tout caractère accentué, remplacent systématiquement l'espace
par le caractère de soulignement, et évitent d'utiliser les termes réservés. Rappelons que
l'implémentation de SQL par Access accepte les caractères accentués pour les noms des
champs et des tables.
Attention aux détails de syntaxe ! Comme tous les langages informatiques, SQL
a ses petites manies qui empoisonnent les utilisateurs. L'interface graphique a ceci de bon
qu'elle nous débarrasse de ces problèmes stupides -- en plus du fait qu'elle nous permet de
créer des requêtes plus simplement et plus rapidement. On notera que, dans Access, le point-
virgule qui marque la fin d'une commande n'est pas indispensable.
3 - La requête avec création de table
Récupérons la requête précédente dans l'interface graphique, faisons en sorte
qu'elle crée une table appelée "Essai", puis basculons en mode SQL. Nous obtenons :
SELECT [Link], [Link]énom INTO Essai
FROM Personnes;
Nous voyons que la création de la table est effectuée grâce à la clause INTO,
suivi du nom de la table. En SQL version Oracle, on écrirait plutôt :
INSERT INTO Essai
SELECT [Link], [Link]énom
FROM Personnes;
Dans Access, cette syntaxe fonctionne à condition que la table "Essai" préexiste,
et contienne au moins les champs "Nom" et "Prénom" avec les mêmes propriétés que dans la
table "Personnes". Access effectue alors une requête ajout des deux premières colonnes de la
table "Personnes" à la table "Essai".
Nous voyons que le tri (dans l'ordre croissant) s'obtient grâce à la clause ORDER
BY, suivi des noms des champs. Le tri multiple est effectué dans l'ordre d'énumération des
champs.
Le tri d'un champ dans l'ordre décroissant s'obtient en faisant suivre le nom de ce
champ par l'opérateur DESC. L'exemple suivant effectue un tri croissant sur les noms, suivi
d'un tri décroissant sur les prénoms :
SELECT [Link], [Link]énom
FROM Personnes
ORDER BY [Link], [Link]énom DESC;
© TIBB imbwangatroptard@[Link]
13
SQL
5 - L'élimination des doublons
Comme nous l'avons vu au chapitre 8, la requête simple peut créer des doublons,
et il est possible de remédier de façon simple à cette situation en jouant sur les propriétés de la
requête. Créons dans l'interface graphique une requête de sélection simple qui concerne le
seul champ "Nom" de la table "Personnes". Modifions la propriété "Valeurs distinctes" de
"Non" à "Oui", puis basculons en mode SQL. Nous obtenons :
SELECT DISTINCT [Link]
FROM Personnes;
Pour éviter de créer des doublons sur deux champs, la commande SQL s'écrit :
SELECT DISTINCT [Link], [Link]énom
FROM Personnes;
7 - La requête multi-fonctionnelle
En définitive, nous pouvons regrouper toutes les opérations précédentes (requête
simple, création de table, création de champ, tri et élimination des doublons) en une seule
requête, dont voici le code SQL (en version Access) :
SELECT DISTINCT [Nom] & " " & [Prénom] AS Nom_complet INTO Liste_de_noms
FROM Personnes
ORDER BY [Nom] & " " & [Prénom];
© TIBB imbwangatroptard@[Link]
14
SQL
SELECT Requê[Link]
FROM Requête1;
On ne peut pas rêver plus simple pour emboîter deux requêtes ! Cette belle
simplicité ne se retrouve pas en SQL pur et dur, où l'emboîtement de deux requêtes est d'une
écriture plutôt complexe. Que l'on en juge :
si la première requête (encore appelée sous-requête, ou sous-interrogation) ramène
une valeur numérique unique (résultat d'une opération du type comptage, sommation, calcul
de moyenne, etc.), on utilise les opérateurs arithmétiques usuels : =, <, >, >=, <= et <> ;
si la première requête ramène une seule ligne, on utilise les opérateurs IN, ALL, ou
ANY suivant les cas ;
si la première requête est susceptible de ramener plusieurs lignes, on utilise EXISTS
ou NON EXISTS.
9 - Conclusion
Le chapitre 11 est consacré à la sélection simple, mise en oeuvre à l'aide de
l'interface graphique d'Access. Le présent chapitre 19 suit pratiquement le même plan, mais
utilise le langage SQL. La comparaison entre ces deux chapitres nous amène à faire une
double constatation :
le langage SQL est d'un usage assez facile, sauf en ce qui concerne l'emboîtement des
requêtes. Pour réaliser l'emboîtement, l'utilisation de l'interface graphique d'Access est
beaucoup plus simple. Cette situation résulte du fait que le SQL mis en oeuvre par Access
permet d'évoquer une requête par son nom, ce qui n'est pas le cas du SQL usuel ;
Access fournit un moyen didactique commode pour aborder l'étude du langage SQL.
© TIBB imbwangatroptard@[Link]
15
SQL
Comme pour les autres chapitres, nous utilisons le SGBD Access comme
support pratique de ce tutoriel (ou tutorial, ou cours en ligne).
Chaque fois que cela sera possible, nous ferons écrire le code SQL par le SGBD,
en partant de l'interface graphique de définition des requêtes avant de basculer en mode SQL.
2 - La sélection en SQL
La sélection permet d'extraire d'une table (ou de plusieurs tables liées par des
relations) les enregistrements répondant à un ou plusieurs critères. Notons au passage qu'un
critère peut aussi être appelé une condition. Rappelons que l'ensemble des critères définit un
filtre.
A titre de premier exemple, cherchons dans la table "Personnes" (qui contient
des noms, des prénoms, des adresses, etc.) les personnes dont le nom commence par la lettre
"c" (majuscule ou minuscule, la casse n'importe pas). Dans la grille de création de la requête,
nous exprimons la condition sous la forme :
Comme "c*"
Si nous basculons en mode SQL, nous obtenons le code suivant :
SELECT [Link], [Link]énom
FROM Personnes
WHERE ((([Link]) Like "c*"));
elle fonctionne tout aussi bien, et le SGBD Access ne tente de rétablir ni les
parenthèses, ni la qualification.
© TIBB imbwangatroptard@[Link]
16
SQL
Rajoutons un champ de type date dans la table "Personnes", et sélectionnons les
enregistrements relatifs à l'année 2002 seule. Dans l'interface graphique, nous écrivons le
critère sous la forme :
>#31/12/2001# ET <#01/01/2003#
Si nous basculons en mode SQL, nous obtenons le code suivant, après
élimination des parenthèses et de la qualification :
SELECT Nom, Prénom, Date
FROM Personnes
WHERE Date>#12/31/2001# And Date<#1/1/2003#;
3 - Les jointures
Effectuons maintenant une requête sur deux tables ("Personne" et "Communes")
liées par une relation (appliquée aux champs "code_commune"). La requête SQL s'écrit :
SELECT [Link], [Link]énom, [Link], [Link],
Communes.[code postal]
FROM Communes INNER JOIN Personnes ON Communes.code_commune =
Personnes.code_commune;
Cette fois, la qualification est obligatoire pour les champs "code_commune", car
il faut préciser de quelle table provient chaque champ. Mais la qualification est inutile pour
les autres champs, car il ne peut y avoir d'ambiguïté. Enfin, les crochets sont obligatoires pour
évoquer le champ "code postal", dont le nom contient un espace (ils ne le sont pas pour
"Prénom", parce que Access tolère les caractères accentués). La requête SQL ainsi simplifiée
s'écrit :
© TIBB imbwangatroptard@[Link]
17
SQL
SELECT Nom, Prénom, Adresse, commune, [code postal]
FROM Communes INNER JOIN Personnes ON Communes.code_commune =
Personnes.Code_commune;
Nous voyons que "INNER JOIN" traduit l'existence d'une relation entre les deux
tables, et que "ON" précise quels sont les champs mis en relation.
En SQL1, la commande précédente s'écrit différemment. La clause INNER JOIN
disparaît au profit d'une simple virgule, et la traduction de la mise en relation des tables
s'exprime à l'aide de la clause WHERE :
SELECT Nom, Prénom, Adresse, commune, [code postal]
FROM Communes, Personnes
WHERE Communes.code_commune = Personnes.code_commune;
Le SGBD Access accepte cette syntaxe mais, si nous revenons dans l'interface
graphique, nous constatons que cette dernière a changé : la relation entre les deux tables a
disparu ! Elle est remplacée par la condition d'égalité de contenu entre les champs
"code_commune" des deux tables (condition exprimée en utilisant la syntaxe du SQL),
comme le montre la figure ci-dessous -- une façon élémentaire, mais parfaitement exacte, de
créer une relation entre deux tables. On notera que la relation normale entre les deux tables
n'est pas supprimée, mais simplement éliminée de la fenêtre de création de la requête.
La clause INNER JOIN a fait son apparition avec la version 2 de SQL, parce que
le besoin s'était fait sentir de préciser à quel type de jointure appartenait une relation. Plus
précisément, on distingue :
la jointure interne, qui utilise INNER JOIN. Ne sont incluses dans le résultat final
que les lignes qui se correspondent dans les deux tables. Ce cas est celui que nous avons traité
précédemment ;
la jointure externe gauche, dans laquelle INNER JOIN est remplacé par LEFT
OUTER JOIN. Toutes les lignes de la première table sont incluses dans le résultat de la
requête, même s'il n'existe pas de ligne correspondante dans la seconde table ;
la jointure externe droite, dans laquelle INNER JOIN est remplacé par RIGHT
OUTER JOIN. Toutes les lignes de la seconde table sont incluses dans le résultat de la
requête, même s'il n'existe pas de ligne correspondante dans la première table.
© TIBB imbwangatroptard@[Link]
18
SQL
Dans Access, la syntaxe des jointures gauche et droite est simplifiée en LEFT
JOIN et RIGHT JOIN, comme le montrent les deux exemples suivants :
SELECT Nom, Prénom, Adresse, commune, [code postal]
FROM Personnes LEFT JOIN Communes ON Communes.code_commune =
Personnes.Code_commune;
SELECT Nom, Prénom, Adresse, commune, [code postal]
FROM Personnes RIGHT JOIN Communes ON Communes.code_commune =
Personnes.Code_commune;
4 - Le regroupement
Nous avons étudié le regroupement au chapitre 14. Nous réutilisons la même
table, intitulée "Résultats" et représentée ci-dessous.
Date Agence CA
06/01/2003 Nord 927,02 €
06/01/2003 Sud 1 098,46 €
06/01/2003 Est 561,29 €
07/01/2003 Nord 1 385,55 €
07/01/2003 Est 681,09 €
07/01/2003 Sud 1 401,56 €
Nous effectuons le regroupement par date et nous sommons sur le CA. Nous
obtenons le code SQL suivant :
SELECT Date, Sum(CA) AS CA_total
FROM Résultats
GROUP BY Date;
dans lequel le regroupement est exprimé par la clause GROUP BY. La requête
fournit le résultat suivant :
Date CA_total
06/01/2003 2 586,77 €
07/01/2003 3 468,20 €
Nous avons vu au chapitre 14 qu'une requête avec regroupement peut être filtrée
avant ou après regroupement. Nous créons un exemple de filtrage avant regroupement en
éliminant l'agence Est. Nous obtenons le code SQL suivant :
SELECT Date, Sum(CA) AS CA_total
FROM Résultats
WHERE Agence Not Like "Est"
GROUP BY Date;
© TIBB imbwangatroptard@[Link]
19
SQL
Nous reconnaissons une requête de sélection classique (dans les trois premières
lignes), suivie d'un regroupement. La requête fournit le résultat suivant :
Date CA_total
06/01/2003 2 025,48 €
07/01/2003 2 787,11 €
Date CA_total
07/01/2003 2 787,11 €
Date Agence CA
06/01/2003 Nord 927,02 €
06/01/2003 Sud 1 098,46 €
06/01/2003 Est 561,29 €
07/01/2003 Nord 1 385,55 €
07/01/2003 Est
07/01/2003 Sud 1 401,56 €
© TIBB imbwangatroptard@[Link]
20
SQL
Nous voyons que le comptage est effectué par la fonction Count(). Le résultat de
la requête est le suivant (la fonction de comptage ignore les Null) :
Date Nombre_CA
06/01/2003 3
07/01/2003 2
Date Doublons_Date
06/01/2003 3
07/01/2003 3
On notera que les deux champs doivent figurer dans la clause de regroupement.
On notera également que l'argument de la fonction Count() devient l'astérisque, ce qui signifie
que l'on compte les lignes sans se référer à une colonne particulière. Le code ci-dessus fournit
le résultat suivant (il n'y a pas de doublons) :
© TIBB imbwangatroptard@[Link]
21
SQL
Le regroupement sans comptage nous permet d'éliminer les doublons. Si nous
effectuons l'opération sur la colonne "Agence", nous obtenons la liste des agences. Le code
SQL s'écrit :
SELECT Agence
FROM Résultats
GROUP BY Agence;
La requête fournit le résultat suivant (les agences sont triées par ordre
alphabétique) :
Agence
Est
Nord
Sud
Comptage
5 - Conclusion
Comme dans le chapitre précédent, le langage SQL ne nous a pas permis
d'effectuer des requêtes qui eussent été impossibles dans l'interface graphique d'Access. Il
nous a cependant permis de simplifier la recherche des doublons (Cf le chapitre 15). Une
commande SQL plus simple s'exécute plus vite, et la différence de temps devient sensible
lorsqu'on traite un grand volume de données.
De ces trois opérations, seule l'union présente vraiment de l'intérêt. Si, dans les
exposés relatifs à SQL, on regroupe généralement les trois opérations ensemblistes, c'est pour
se conformer à une logique mathématicienne. Comme nous le verrons dans la suite de ce
chapitre, l'intersection et la différence sont en fait des requêtes multi-tables particulières, que
© TIBB imbwangatroptard@[Link]
22
SQL
l'on peut réaliser même si l'on ne dispose pas d'une commande spécifique -- ce qui est
effectivement le cas lorsqu'on utilise le SGBD Access.
La requête union, par contre, est quasi irremplaçable : elle seule permet de
mettre deux tables bout à bout en leur faisant jouer des rôles identiques, et en éliminant
systématiquement les doublons. Certes, la requête ajout permet d'ajouter une table à une autre,
mais dans ce cas les deux tables ne jouent pas le même rôle, et l'élimination des doublons -- si
elle s'avère nécessaire -- requiert soit la création d'un index multi-champ, soit un traitement
ultérieur (regroupement).
A ce chapitre nous rajouterons un paragraphe concernant le produit cartésien de
deux tables, requête qui n'est utilisée que très rarement et dans des cas très spécifiques.
Comme pour les autres chapitres de ce tutoriel (ou tutorial, ou cours en ligne),
nous utiliserons le SGBD Access comme support pratique.
nom prénom
Chose Jules
Machin Pierre
Truc Patrick
union nom prénom
Pouf Jean
Chose Jules
= nomprénom
Chose Jules
Machin Pierre
Pouf Jean
Truc Patrick
Il n'existe pas dans Access d'interface graphique permettant de créer une requête
Union. Il faut donc écrire soi-même le code SQL requis. Pour ouvrir l'éditeur de requêtes
SQL, nous sélectionnons l'objet "Requêtes" dans la fenêtre "Base de données", nous
n'introduisons aucune table dans l'interface graphique de définition des requêtes, et nous
basculons en mode SQL.
© TIBB imbwangatroptard@[Link]
23
SQL
Si notre base contient les deux tables précitées, nous pouvons exécuter la requête
SQL suivante, contenant l'opérateur UNION :
SELECT nom, prénom
FROM Table1
UNION
SELECT nom, prénom
FROM Table2;
Exemple 3. Nous pouvons faire en sorte d'imposer les noms des champs dans la
feuille de données résultante pour obtenir, par exemple, le résultat suivant :
nom prénom
Chose Jules
Machin Pierre
© TIBB imbwangatroptard@[Link]
24
SQL
Truc Patrick
union nom prénom
Pouf Jean
Chose Jules
= Col1Col2
Chose Jules
Machin Pierre
Pouf Jean
Truc Patrick
© TIBB imbwangatroptard@[Link]
25
SQL
Exemple 5. Pour faire en sorte que la requête union n'élimine pas les doublons,
nous rajoutons l'opérateur ALL après UNION, comme le montre la requête ci-dessous :
SELECT nom, prénom
FROM Table1
UNION ALL
SELECT nom, prénom
FROM Table2;
La feuille de données obtenue résulte de la simple mise bout à bout des deux
tables, sans tri ni élimination des doublons :
nom prénom
Chose Jules
Machin Pierre
Truc Patrick
union all nom prénom
Pouf Jean
Chose Jules
= Col1Col2
Chose Jules
Machin Pierre
Truc Patrick
Pouf Jean
Chose Jules
Exemple 6. Comment faire en sorte que la requête Union crée une table ? Une
des techniques possibles consiste à emboîter la requête union dans une commande d'insertion.
Le code SQL suivant :
INSERT INTO Table3
SELECT *
FROM (SELECT nom, prénom
FROM Table1
UNION SELECT [last-name], [first-name]
FROM Table2);
peut être exécuté à condition que la table "Table3" ait été préalablement créée
(vide) -- mais cette condition n'est pas requise pour observer le résultat de la requête en mode
feuille de données. La requête ci-dessus est reconnue par le SGBD Access comme une requête
"Ajout" (à cause de la clause INSERT) et, si nous l'enregistrons, son nom apparaît précédé de
l'icône correspondante. Le code ci-dessus nous offre un exemple d'emboîtement en SQL.
Cet aspect didactique mis à part, il est plus simple, quand on opère dans le
SGBD Access, de réaliser d'abord la requête union, puis de réutiliser son résultat dans une
requête de sélection simple, à laquelle on demande de créer une table.
© TIBB imbwangatroptard@[Link]
26
SQL
Remarque. Si nous tentons de réaliser l'union de deux tables contenant un
champ (nommé "essai") de type Mémo, Objet OLE ou Lien hypertexte, nous obtenons le
message suivant (rédigé dans le jargon franglais des informaticiens) :
Cela signifie que, dans le SGBD Access, la requête Union ne fonctionne pas sur
les champs de type Mémo, Objet OLE et Lien hypertexte. Pour réunir deux tables comportant
des champs de ce type sans les perdre, il faut utiliser la requête Ajout.
La requête Union présente un autre défaut : elle est lente à l'exécution, aussi bien
programmée soit-elle. Cela provient du fait qu'elle trie et dédoublonne, alors que la requête
Ajout se contente de compléter une table avec les données d'une autre. A titre d'exemple, sur
un PC de qualité standard, il faut environ plusieurs minutes (3-4) pour réaliser l'union de
10.000 enregistrements avec 300.000 autres.
nom prénom
Chose Jules
Machin Pierre
Truc Patrick
inter nom prénom
Pouf Jean
Chose Jules
= nom prénom
Chose Jules
Cette syntaxe, qui fait appel à l'emboîtement autant de fois qu'il y a de colonnes,
a été simplifiée par l'introduction de l'opérateur INTERSECT en SQL2. Le nouveau code
s'écrit :
SELECT nom, prénom
FROM Table1
INTERSECT
© TIBB imbwangatroptard@[Link]
27
SQL
SELECT nom, prénom
FROM Table2;
Comme on peut le constater, il est possible d'utiliser des critères écrits en code
SQL dans l'interface graphique. Ma foi, autant utiliser la fenêtre SQL directement !
Que l'opérateur INTERSECT ne soit pas reconnu par Access n'est pas un drame.
Outre les deux commandes SQL déjà citées, nous en imaginer une troisième, qui résulte
directement de la définition de l'intersection :
SELECT DISTINCT [Link], [Link]énom
FROM Table1, Table2
WHERE [Link]=[Link] AND [Link]énom=[Link]énom;
© TIBB imbwangatroptard@[Link]
28
SQL
seconde table est identique à celui de la première table, nous utilisons l'opérateur "Est Pas
Null". Dans l'interface graphique, la requête apparaît comme le montre la figure ci-dessous.
nom prénom
Chose Jules
Machin Pierre
Truc Patrick
diff nom prénom
Pouf Jean
Chose Jules
= nomprénom
Machin Pierre
Truc Patrick
© TIBB imbwangatroptard@[Link]
29
SQL
WHERE [Link] NOT IN (SELECT nom FROM Table2) AND [Link]énom NOT IN
(SELECT prénom FROM Table2);
(dans l'interface graphique de définition des requêtes, "Not In" devient "Pas In"
-- un joyeux mélange de français et d'anglais).
La syntaxe précédente, qui fait appel à l'emboîtement autant de fois qu'il y a de
colonnes, a été simplifiée par l'introduction de l'opérateur EXCEPT dans SQL2 (MINUS dans
le SGBD Oracle). Le nouveau code s'écrit :
SELECT nom, prénom
FROM Table1
EXCEPT
SELECT nom, prénom
FROM Table2;
La jointure gauche est nécessaire parce qu'il faut que le SGBD, lors de
l'exécution de la requête, utilise tous les enregistrements de la première table, qu'ils soient ou
non présents dans la seconde. Si nous utilisions la jointure interne, le SGBD n'examinerait que
les enregistrements communs, et n'en retiendrait évidemment aucun. Si nous utilisions la
jointure droite, le SGBD utiliserait tous les enregistrements de la deuxième table, mais
seulement ceux de la première table qui sont communs, et le résultat serait de nouveau vide.
Le choix du type de jointure vous pose problème ? Essayez les trois types sur un
exemple simple, vous trouverez ainsi quel est celui qui donne la réponse juste.
© TIBB imbwangatroptard@[Link]
30
SQL
nom
Chose
Machin
X prénom
Jean
Jules
= nomprénom
Chose Jean
Chose Jules
Machin Jean
Machin Jules
6 - Conclusion
Il est clair que les concepteurs du SGBD Access n'aimaient pas les ensembles.
Car si l'opérateur UNION est reconnu (mais inutilisable dans l'interface graphique) par le
logiciel, les opérateurs INTERCEPT et EXCEPT (ou MINUS) sont ignorés. Pour réaliser une
intersection ou une différence dans Access, la solution la plus simple consiste à utiliser les
jointures (sans se tromper), associées à des conditions sur le Null. Il faut cependant
reconnaître que, des trois opérations ensemblistes, seule la requête Union a vraiment de
l'importance.
Rappelons pour terminer que, dans une requête Union, les deux tables jouent le
même rôle, contrairement à ce qui se passe dans la requête "Ajout". De plus, aucune des deux
tables n'est modifiée par l'exécution de la requête, et les doublons sont automatiquement
© TIBB imbwangatroptard@[Link]
31
SQL
éliminés, à moins que nous ne demandions à les conserver. La requête union mérite à elle
seule que l'on se familiarise un peu avec le SQL.
Pour créer des exemples, nous utiliserons la table suivante, intitulée "Table1" :
Nom Prénom
Chose Jules
Machin Pierre
Truc Patrick
Pouf Renée
Attention ! Toutes les requêtes que nous allons utiliser modifient les tables
auxquelles elles s'appliquent. Il est donc vivement recommandé de créer une copie de la table
avant d'exécuter la requête.
Comme pour les autres chapitres de ce tutoriel (ou tutorial, ou cours en ligne),
nous utiliserons le SGBD Access comme support pratique.
2 - La suppression
Rappelons qu'une requête de suppression opère sur une table, dont elle supprime
les enregistrements (ou lignes) répondant à un ou plusieurs critères.
En SQL, c'est la commande DELETE qui permet de supprimer des lignes dans
une table. La clause WHERE permet d'exprimer les conditions (critères) de cette suppression.
Pour supprimer la dernière ligne de la table "Table1", nous créons la requête
SQL suivante :
DELETE Table1
WHERE Nom="Pouf";
Mais le SGBD Access n'accepte pas cette syntaxe. Si nous créons la requête de
suppression dans l'interface graphique, sa traduction en SQL donne :
DELETE Nom
FROM Table1
WHERE Nom="Pouf";
© TIBB imbwangatroptard@[Link]
32
SQL
Machin Pierre
Truc Patrick
Pouf Renée
-- Suppression --> Nom Prénom
Chose Jules
Machin Pierre
Truc Patrick
Mais cette syntaxe manque de logique. Ce n'est pas dans le seul champ "Nom"
que nous opérons une suppression, c'est toute la ligne comportant le nom "Pouf" qui disparait.
C'est probablement pour faciliter la correspondance avec l'interface graphique que l'éditeur
Microsoft a pris des libertés avec la syntaxe de la requête suppression en SQL, ce qui est
regrettable.
Tout ce que nous avons dit sur l'expression des critères dans les requêtes de
sélection s'applique aux requêtes de suppression. En résumé, la syntaxe d'une requête de
suppression est :
SQL normalisé DELETE nom de la table
WHERE critères des suppressions;
3 - La mise à jour
Rappelons qu'une requête de mise à jour modifie le contenu d'une colonne dans
une table donnée. Cette modification peut être soumises à des critères, de telle sorte qu'elle ne
s'applique pas à toutes les lignes.
En SQL, c'est la commande UPDATE qui permet de modifier (ou mettre à jour)
les données d'une table. La clause SET est utilisée pour préciser la modification demandée, et
la clause WHERE les conditions d'application (critères) de cette modification.
Supposons par exemple que, dans la table "Table1", nous ayons commis une
erreur en saisissant le prénom de M. Chose. Pour remplacer "Jules" par "Henri", dans la
colonne "Prénom", sur la ligne relative à M. Chose, nous utilisons la requête SQL suivante :
UPDATE Table1
SET Prénom = "Henri"
WHERE Nom="Chose";
© TIBB imbwangatroptard@[Link]
33
SQL
L'exécution de cette requête modifie la table "Table1" comme suit :
Nom Prénom
Chose Jules
Machin Pierre
Truc Patrick
-- Mise à jour --> Nom Prénom
Chose Henri
Machin Pierre
Truc Patrick
Exemple : pour augmenter de 20 % tous les prix contenus dans la colonne "Prix"
d'une table intitulée "Table2", nous utilisons la requête ci-dessous. On notera qu'il n'est pas
nécessaire, pour évoquer le contenu du champ "Prix", de placer son nom entre crochets.
UPDATE Table2
SET Prix = Prix*1.2;
© TIBB imbwangatroptard@[Link]
34
SQL
INSERT INTO Table3 ( Col1, Col2 )
SELECT Nom, Prénom
FROM Table1;
Grâce à cette syntaxe, le SGBD sait que les données du champ "Nom" de la table
"Table1" vont dans le champ "Col1" de la table "Table3", et les données du champ "Prénom"
de la table "Table1" dans le champ "Col2" de la table "Table3". Il faut bien sûr que les types
de données soient compatibles. Par exemple, on peut introduire une date dans un champ texte,
mais l'inverse est généralement impossible. Il faut aussi faire attention à la façon dont on fait
correspondre les champs. Il n'est pas nécessaire qu'ils se présentent dans le même ordre dans
les deux tables, pourvu que la commande SQL indique clairement comment on les met en
correspondance. Il n'est pas nécessaire non plus que les champs qui se correspondent portent
le même nom.
La requête précitée réalise l'opération suivante :
Nom Prénom
Chose Henri
Machin Pierre
Truc Patrick
+ Col1 Col2
Titi Noëlle
= Col1Col2
Titi Noëlle
Chose Henri
Machin Pierre
Truc Patrick
les prénoms iront dans la colonne "Col1" et les noms dans la colonne "Col2".
On peut rajouter un ou plusieurs critères (via la clause WHERE) permettant de
sélectionner les enregistrements à ajouter. La requête ci-dessous, par exemple, ajoutera
seulement Chose Henri à la table "Table3".
INSERT INTO Table3 ( Col1, Col2 )
SELECT Nom, Prénom
FROM Table1
WHERE Nom<"d";
© TIBB imbwangatroptard@[Link]
35
SQL
5 - Conclusion
Nous avons appris à créer des requêtes de suppression, de mise à jour et d'ajout
en SQL. Dans le cas particulier du SGBD Access, la syntaxe de la requête de suppression
n'est pas très claire. Les requêtes de mise à jour et d'ajout ont par contre une syntaxe qui
respecte le SQL normalisé.
Certains utilisateurs pourront donc trouver utile de basculer en mode SQL pour
vérifier, avant exécution, si la requête de mise à jour ou d'ajout qu'ils viennent de créer dans
l'interface graphique répond bien à leurs desiderata.
© TIBB imbwangatroptard@[Link]
36
SQL
les bases de données contiennent souvent des quantités considérables d'information, et
il n'est pas question de tout imprimer. Il faut donc commencer par sélectionner l'information
particulière que l'on veut reproduire avant d'imprimer ;
dans une BDD relationnelle, l'information est répartie dans des tables multiples, et il
faut la rassembler avant de l'imprimer. On peut, cependant, introduire dans un même état des
champs provenant de plusieurs tables, à condition que ces dernières soient liées par des
relations ;
on peut désirer que l'information imprimée se présente dans un certain ordre. Il faut
donc opérer un tri plus ou moins complexe avant d'imprimer. Ceci dit, on peut également
demander un tri complexe (jusqu'à quatre niveaux) lors de la création de l'état.
2 - Les préliminaires
La finalité de l'état étant la réalisation d'une sortie imprimée, il est indispensable
d'indiquer au SGBD :
l'imprimante utilisée ;
la taille de la zone imprimable, c'est à dire celle du papier, diminuée de celle des
marges.
Nous rencontrons ici l'une des différences importantes qui existent entre l'état et
le formulaire : le premier opère dans une zone imprimable, le second dans une fenêtre de
l'écran du moniteur.
L'imprimante. Le SGBD construit l'état en fonction des caractéristiques de
l'imprimante par défaut. Si vous utilisez un poste de travail sur lequel aucune imprimante n'a
été déclarée, vous allez au-devant de bien des ennuis (lenteur, plantage...). Vérifiez donc ce
point avant d'entreprendre la création d'un état.
La zone imprimable. Ensuite, le SGBD tient compte des options que vous avez
choisies -- ou, plus généralement, conservées par défaut -- en ce qui concerne la taille du
papier (A4, sauf exception) et les marges d'impression. Si vous manquez de place en largeur
-- ce qui est souvent le cas lorsqu'un état est présenté en colonnes -- vous avez intérêt à
réduire les marges à gauche et à droite. Mais attention ! vous devez effectuer cette opération
© TIBB imbwangatroptard@[Link]
37
SQL
avant de commencer à construire votre état. Une fois ce dernier créé, les changements de
marge que vous effectuez sont sans effet sur lui.
Dans Access, pour régler les marges, cliquez dans le menu sur "Outils", puis
"Options..." : la fenêtre "Options" s'ouvre. Choisissez l'onglet "Général" : les quatre marges
sont réglées par défaut à un pouce (2,54 cm). En pratique, 2 cm à gauche et 1 cm à droite
suffisent largement. Quelles que soient les valeurs que vous choisissez, elles resteront
valables quelle que soit la BDD dans laquelle vous travaillez, tant que vous ne les modifierez
pas à nouveau.
La sélection des données. Mettez au point la (ou les) requête(s) qui vous
permettent de sélectionner les données à imprimer. Si vous avez besoin d'un tri, incorporez-le
à ce stade, car les tris que l'on demande au niveau des états ne fonctionnent pas toujours très
bien. Enfin, vous n'êtes pas obligé de créer une table, un état pouvant être construit
directement sur le résultat d'une requête.
La présentation des données. Il existe deux modes de présentation d'un état :
la présentation tabulaire : les données sont disposées dans des colonnes verticales,
comme dans une table. Le nom des colonnes (l'étiquette) figure une seule fois par page. Cette
présentation, qui convient particulièrement bien aux données numériques, économise de la
place ;
la présentation verticale : les données relatives à chaque champ sont imprimées les
unes en dessous des autres, le nom du champ étant rappelé à chaque fois. Cette présentation
est la seule possible lorsque le contenu de certains champs est volumineux. Elle peut faire
l'objet d'un regroupement sur une colonne donnée, si cette dernière contient de nombreux
doublons. Elle présente l'inconvénient de requérir beaucoup de place.
3 - La création de l'état
Ouvrons une BDD contenant au moins une table pourvue de données et, dans la
fenêtre "Base de données", sélectionnons l'objet "États". Deux options nous sont présentées :
Créer un état en mode Création
Créer un état à l'aide de l'Assistant
© TIBB imbwangatroptard@[Link]
38
SQL
État instantané : Colonnes. Cette fonction crée un état en présentation verticale dès
que nous lui fournissons le nom de la table ou de la requête. Nous ne sommes pas maître des
paramètres, et le résultat est sommaire ;
État instantané : Tableau. Cette fonction opère comme la précédente, mais en
présentation tabulaire ;
Assistant graphique. Cette fonction permet de créer des graphiques, mais leur qualité
est très mauvaise. Pour créer un graphique correct, il faut exporter les données vers un
tableur ;
Assistant étiquette. Comme son nom l'indique, cette fonction permet d'imprimer des
étiquettes.
Lançons l'assistant, choisissons une table ("Personnes", avec les champs "Nom"
et "Prénom"), sélectionnons ses deux champs, ignorons le regroupement et le tri, adoptons la
disposition tabulaire, l'orientation portrait et le style "Informel" (valeurs par défaut), donnons
un titre à l'état ("Liste des personnes"), et cliquons sur "Terminer". Nous obtenons un état qu'il
est souhaitable d'améliorer.
4 - La structure de l'état
L'état que nous venons de créer apparaît dans la fenêtre "Base de données"
(l'objet "État" étant sélectionné). Nous le sélectionnons, puis nous cliquons sur l'icône
"Modifier". Une fenêtre s'ouvre, qui nous permet de modifier l'état.
Procédons d'abord à une petite vérification. Notre imprimante utilise du papier
A4 de 21 cm de large, et nous avons choisi des marges gauche et droite importantes (5 cm)
afin de limiter la taille de la figure ci-dessous. Nous vérifions que la largeur utile de l'état (la
partie claire et quadrillée) mesure effectivement 11 cm, comme le montre la figure. Même si
nous modifions par la suite les marges dans la fenêtre "Options", celles de notre nouvel état ne
varieront pas.
© TIBB imbwangatroptard@[Link]
39
SQL
En-tête d'état. Cette zone est imprimée en haut de la première page uniquement ;
En-tête de page. Cette zone est imprimée en haut de toutes les pages (à condition
qu'elle contienne de l'information) ;
Détail. Ce terme désigne la zone qui s'étend entre l'en-tête et le pied de page. Cette
zone permet d'imprimer le contenu de la table (ou de la feuille de données) sous-jacente ;
Pied de page. Cette zone est imprimée en bas de chaque page ;
Pied d'état. Cette zone s'imprime uniquement sur la dernière page, après le détail et
avant le pied de page. Par défaut, l'assistant lui attribue une hauteur nulle.
De manière quelque peu schématique, on peut dire que les diverses zones sont
utilisées de la manière suivante :
la première zone (en-tête d'état) contient le titre, de telle sorte qu'il n'apparaisse qu'une
seule fois, et qu'il se trouve en tête de l'état ;
dans une présentation tabulaire, les noms des champs (on les appelle les "étiquettes")
sont placés dans la seconde zone (en-tête de page), de manière à être reproduits en haut de
chaque page. Dans une présentation verticale, les étiquettes sont regroupées avec les champs
correspondants dans la zone "Détail", et l'assistant ne prévoit pas d'utiliser l'en-tête de page ;
les champs (on les appelle "zones de texte", ou parfois "contrôles" comme dans les
formulaires) sont placés dans la troisième zone (détail) ; leurs valeurs sont imprimées ligne
après ligne, tant qu'il reste de la place entre l'en-tête et le pied de chaque page. Le SGBD
passe ensuite à la page suivante, et le processus recommence ;
dans la quatrième zone (pied de page), le système pagine et inscrit la date. Ces
informations apparaissent donc en bas de chaque page.
la cinquième zone (pied d'état) contient les résultats de calculs éventuels, ou un
message de fin d'état.
© TIBB imbwangatroptard@[Link]
40
SQL
Détail Zone 3
En-têteÉtat Zone 1
État
Étiquette4 Zone de texte indépendante Titre de l'état
Nom Zone de texte dépendante Contenu du champ "Nom"
Nom_étiquette Étiquette Étiquette du champ "Nom"
Pied État Zone 5
Prénom Zone de texte dépendante Contenu du champ "Prénom"
Prénom_étiquette Étiquette Étiquette du champ "Prénom"
Texte5 Zone de texte calculée Affiche la date du jour
Texte6 Zone de texte calculée Affiche la pagination
Trait7 Zone de texte indépendante Le pointillé supérieur
Trait8 Zone de texte indépendante Le pointillé inférieur
ZoneEn-têtePage Zone 2
ZonePiedPage Zone 4
Les barres d'outils. Nous noterons d'abord que la barre de mise en forme est
active lorsqu'une zone de texte est sélectionnée. Cette barre contient les outils usuels du
traitement de texte (propriété de la police, alignement du texte, couleur de fond et de premier
plan, bordures). Elle contient en outre (tout à fait à gauche) la liste des objets de l'état, liste
dont nous avons déjà parlé au paragraphe 4 précédent.
Lorsque nous modifions la présentation d'un état, il nous faut régulièrement
vérifier le résultat obtenu, car ce qui s'affiche est souvent différent de ce qui s'observe en
mode "Modifier". Pour cela, nous cliquons sur l'icône "Aperçu" de la barre d'outils "Créer
un état".
Cette barre contient également deux autres icônes fort utiles. L'icône "Liste des
champs" permet de rajouter de nouveaux champs à l'état, par simple glisser-déplacer (de la
liste vers l'état). L'icône "Propriétés" permet d'afficher la feuille de propriétés de l'objet
sélectionné dans l'état.
Ces feuilles de propriétés nous sont fort utiles, car dans leur onglet "Format"
nous pouvons :
© TIBB imbwangatroptard@[Link]
41
SQL
régler la position des quatre coins du rectangle contenant une zone de texte. L'origine
des coordonnées correspond au coin situé en haut et à gauche de la zone dans laquelle se
trouve la zone de texte ;
régler les marges et l'interligne (à l'intérieur de la zone de texte) ;
colorer le fond ou le rendre transparent ;
régler la bordure (couleur, épaisseur) et l'apparence (3D, ombré, etc.) ;
fixer tous les attributs du texte, comme dans un traitement de texte.
Si nous avons affaire à une zone de l'état, la liste des attributs est évidemment
plus réduite.
La fenêtre graphique nous permet d'effectuer de multiples opérations à l'aide
de la souris :
modifier la taille des différentes zones qui constituent l'état, en tirant sur la barre qui
les sépare, lorsque le curseur prend la forme d'une croix. Appliquée à la zone "Détail",
cette opération a pour effet de modifier l'interligne à l'impression (dans la présentation
tabulaire) ;
déplacer les zones de texte et les étiquettes, soit séparément, soit en les regroupant par
sélection multiple (touche shift enfoncée). Lorsque le curseur prend la forme d'une main
ouverte, toutes les zones sélectionnées sont simultanément déplacées. Lorsque le curseur
prend la forme d'un index pointé, seule la zone concernée est déplacée. Attention ! ne
positionnez pas une zone de texte contre la limite de la zone imprimable, sinon l'imprimante
débitera une page blanche pour chaque page imprimée ;
modifier la taille d'une étiquette ou d'une zone de texte, en tirant sur les sommets ou
les milieux des côtés du rectangle correspondant ;
modifier la largeur de la zone imprimable. Réduisez-la si vous le désirez, mais ne
l'élargissez pas au-delà de sa taille initiale, même si vous avez réduit les marges entre temps.
Sinon, une page blanche accompagnera chaque page imprimée. Un bon conseil : ne touchez
pas à la largeur de la zone imprimable.
© TIBB imbwangatroptard@[Link]
42
SQL
de numéroter les pages et d'imprimer la date et l'heure (si nous avons créé l'état sans
l'aide de l'assistant) ;
d'insérer des graphiques, des images ou des objets divers, que nous pouvons ensuite
placer où nous voulons dans l'état.
Les autres outils -- en particulier ceux qui permettent d'insérer des boutons, des
boutons radio, des cases à cocher, des listes, etc. -- n'ont pas d'utilité pour mettre en forme un
état qui est, par vocation, destiné à être imprimé.
6 - Conclusion
L'état s'avère être un objet utile dans le cas où l'impression de données issues
d'une BDD est une opération récurrente. La création d'un état bien présenté étant une
opération consommatrice de temps, il est préférable d'effectuer les impressions occasionnelles
à l'aide d'un tableur. De plus, l'usage d'un tableur est pratiquement obligatoire lorsqu'on veut
présenter les données sous forme d'un graphique.
Les recommandations qui s'appliquent aux arts graphiques en général sont
également valables pour les états en particulier. Il ne faut pas abuser des images, des fonds
colorés, des polices exotiques et des présentations tarabiscotées. La simplicité, la clarté et la
lisibilité priment.
© TIBB imbwangatroptard@[Link]
43
SQL
(appareils de mesure, lecteurs de codes barres, scanners, etc.), avant de les importer dans une
base.
De plus, on constate une dématérialisation croissante des données échangées
entre les entreprises. Pour les opérations commerciales récurrentes, les bons de commande et
les factures imprimés vont peu à peu disparaître au profit de transmissions directes via
Internet (cela s'appelle le "e-procurement"). Toutes les données résultant de ces transactions
aboutiront dans des BDD par importation.
Il est bien rare que, dans une entreprise d'une certaine taille, toutes les données
soient stockées dans une seule et même BDD (et ce ne serait peut-être pas judicieux de le faire
-- il y a des discussions passionnées sur ce sujet). On est donc fatalement amené à transférer
des données d'une base à une autre. Le cas échéant, il peut être intéressant de transférer des
objets (requêtes, formulaires, états, macros, etc.), c'est à dire des structures et non plus des
données. Enfin, en cas de changement de matériel et/ou de logiciel, on peut être amené à
transférer une base entière d'un système informatique à un autre.
Certains échanges, bien sûr, peuvent être très difficiles à réaliser (entre des
systèmes informatiques n'utilisant pas le même système d'exploitation, par exemple), voire
même impossibles. Les divers SGBD que l'on trouve sur le marché sont plus ou moins
ouverts, et l'étude de l'import/export est donc très spécifique du système utilisé.
Comme pour les autres chapitres de ce tutoriel (ou tutorial, ou cours en ligne),
nous utiliserons le SGBD Access comme support pratique.
Les tableaux n'existant pas dans les fichiers texte, les données d'un même
enregistrement sont rassemblées sur une même ligne (nous supposerons ici que c'est toujours
possible). Le passage d'un champ à l'autre est repéré par un caractère particulier réservé à cet
effet (espace, point virgule, etc.) et appelé caractère de séparation, ou par une tabulation. La
figure ci-dessous représente un exemple d'une telle disposition, où l'espace sert de caractère
de séparation.
Groupe X - Magasin Y
Date : 28/12/2002
Date Heure Caisse Produit Quant. Prix Total
28/12/2002 9:02:31 03 C-168324 1 24,95 24,95
28/12/2002 9:02:35 02 P-2896 3 13,55 40,65
28/12/2002 9:02:41 02 X-12709 1 6,90 6,90
etc......
© TIBB imbwangatroptard@[Link]
44
SQL
informatique du groupe, où il est importé dans une base de données. Le lendemain matin, le
patron trouvera sur son bureau une synthèse des résultats de la veille, générée de manière
entièrement automatique...
Commençons, plus modestement, par importer manuellement un tel fichier dans
Access. Mais avant de commencer, il faut que nous décidions si nous importons dans une
table existante, ou si nous laissons au système le soin d'en créer une. Nous conseillons
vivement la première solution, et ce pour deux raisons :
on règle mieux les propriétés des champs dans la grille de création d'une table que
dans l'assistant d'importation ;
importer dans une table existante revient à réaliser une requête Ajout (les nouvelles
données viennent s'inscrire à la suite des précédentes), et c'est généralement le résultat que
l'on recherche.
Donc, avant d'importer, nous créons une table comportant sept champs (Date,
Heure, N°_caisse, Code_produit, Quantité, Prix_unitaire, Prix_total), dotés des types de
données et des propriétés adéquats, et en évitant les espaces dans leurs noms.
Nous lançons ensuite l'assistant "Importation de Texte" via "Fichier > Données
externes > Importer...". Il faut d'abord préciser l'extension du fichier à importer et son chemin.
On notera au passage la liste des formats qu'Access peut importer (outre le sien propre) :
dBase, Excel, HTML, Outlook, Lotus, Paradox, texte, XML et les formats des SGBD
respectant l'interface ODBC (Open DataBase Connectivity). Cette interface, créée par
Microsoft en 1993, permet à presque tous les SGBD de communiquer lorsqu'ils sont installés
sous Windows (il faut cependant que le pilote ODBC correspondant existe).
L'assistant démarre et nous conseillons de cliquer tout de suite sur le bouton
"Avancé...". La fenêtre "[Nom du fichier] Spécification d'importation" s'ouvre, qui nous
permet de régler tous les détails de l'importation :
Format du fichier : le fichier est-il "délimité" ou de "longueur fixe" ? Le premier cas
correspond à l'usage d'un caractère de séparation, le second à une tabulation. Dans le cas
présent, la réponse est "délimité" ;
Séparateur de champ : il faut indiquer au système quel est le caractère séparateur.
Dans le cas présent, la réponse est "space" ;
Délimiteur de texte : pour différencier les champs de texte des champs numérique, on
place parfois le texte entre des guillemets simples ou doubles. Dans le cas présent, la réponse
est "aucun" ;
Dates, heures et nombres : dans le cas présent, nous laissons les valeurs par défaut ;
Informations sur le champ : ces informations (nom, type de données, indexation)
doivent correspondre avec celles de la table dans laquelle nous allons importer. Le système
propose de ne pas importer le contenu de certains champs ("sauter"), ce qui rend service dans
certains cas.
Avant de quitter cette fenêtre, nous devons enregistrer toutes les informations
qu'elle contient en cliquant sur le bouton "Enregistrer sous..." et donner un nom au format
d'importation personnalisé que nous venons de créer.
Nous poursuivons avec l'assistant. Nous ne cochons pas "Première ligne contient
les noms des champs" pour deux bonnes raisons : ce n'est pas vrai, et les noms des champs
sont déjà déterminés puisque nous importons dans une table existante -- ce que nous
indiquons à l'étape suivant, en précisant le nom de la table (liste déroulante). Nous cliquons
© TIBB imbwangatroptard@[Link]
45
SQL
sur "Terminer", et le système nous prévient que toutes les données n'ont pas été importées
avec succès. La table que nous avions préparée se trouve ainsi remplie :
Les données des trois premières lignes du fichier texte n'ont pas pu être
importées, parce que leur type de données était incompatible (seul "Produit" est passé entre
les mailles). Une table contenant les erreurs d'importation a d'ailleurs été créée, dont voici le
contenu :
Ces erreurs ne se seraient pas produites si nous avions éliminé les trois premières
lignes du fichier avant de l'importer. Il faut cependant bien voir que si l'on importe un fichier
texte de plusieurs centaines de milliers de lignes, la probabilité de rencontrer quelques lignes
erronées n'est pas tout à fait nulle. Une coupure de courant, un incident nécessitant le
redémarrage de l'ordinateur, une machine débordée qui écrit comme elle peut dans son fichier
journal, un petit bug dans le logiciel... et voici créée une ligne qui ne s'importera pas
correctement. Mais la présence d'une à quelques lignes dans la table des erreurs d'importation
ne constitue pas un drame. On peut éliminer facilement les enregistrements déficients de la
table (dans laquelle s'est faite l'importation) à l'aide d'une requête suppression, le critère étant
© TIBB imbwangatroptard@[Link]
46
SQL
que l'un des champs au moins n'est pas renseigné (Est Null), alors qu'il devrait normalement
l'être.
Lorsqu'on importe régulièrement des données possédant la même structure, on
accélère considérablement la procédure en réutilisant le format d'importation. Pour ce faire, il
faut se rendre tout de suite dans la fenêtre des spécifications d'importation, cliquer sur le
bouton "Paramètres...", et choisir le bon format. Toutes les données correspondantes
s'inscrivent d'elles mêmes dans la fenêtre.
On peut encore aller plus vite en automatisant l'importation à l'aide d'une macro,
comme nous le verrons au chapitre 20 suivant.
Si l'on examine les propriétés de la table ainsi créée, on s'aperçoit que, pour les
champs de type texte (Ville, Activité) le système réserve automatiquement la place maximale
(255 caractères), même si aucune des chaînes de caractères importées n'atteint cette taille. On
peut toujours corriger après coup, mais on court le risque de tronquer certaines informations.
Si l'on importe dans une table existante, et qu'une chaîne est trop longue pour le champ, elle
sera là encore tronquée, mais le fait sera signalé dans le fichier des erreurs d'importation.
4 - L'importation d'objets
Tous les objets d'une BDD gérée par Access peuvent être importés dans une
autre base gérée par le même SGBD : tables, requêtes, formulaires, états, macros, modules.
Mais cela ne veut pas dire qu'ils fonctionneront à coup sûr après importation. Une requête, par
exemple, est basée sur une ou plusieurs tables ou feuilles de données. Si nous importons la
© TIBB imbwangatroptard@[Link]
47
SQL
requête, mais que l'une des tables manque, la requête ne peut pas fonctionner, et le système
nous en avertira.
Il arrive souvent que l'on ne s'intéresse qu'à une petite partie d'une grande base
de donnée, par exemple une semaine dans les opérations d'une année. On a alors intérêt à
créer des tables réduites à la semaine en question, puis à les importer dans une nouvelle base
avec tous les autres objets. On pourra effectuer les mêmes opérations que sur la base de
départ, mais avec 52 fois moins de données, ce qui va bien accélérer les opérations.
Pour voir fonctionner l'importation d'objets, nous suivons de nouveau le chemin
"Fichier > Données externes > Importer...". Nous indiquons au système un fichier Access
(.mdb), et la boite de dialogue suivante s'ouvre.
Lorsque tous les objets désirés ont été sélectionnés (en cliquant dessus -- un
nouveau clic désélectionne), on valide par "OK", et l'importation s'effectue.
5 - L'exportation
Dès qu'un objet de la base (ex : table) est sélectionné, la fonction "Fichier >
Exporter..." devient active, et l'on peut se livrer aux opérations inverses de celles décrites ci-
dessus.
© TIBB imbwangatroptard@[Link]
48
SQL
L'exportation d'une table sous forme d'un fichier texte délimité peut servir de
dernier recours pour transférer des données d'une base à une autre, lorsque tous les autres
moyens ont échoué. L'opération d'exportation est sans douleur, il suffit d'indiquer au système
le caractère de séparation que l'on veut utiliser.
L'exportation d'un objet d'une base Access vers une autre base Access ne pose
pas de problème particulier. Si l'objet est une table, le SGBD demande si l'on veut exporter la
structure seule, ou la structure et les données ensemble.
L'échange de données entre Access et Excel est très aisé, et souvent pratiqué.
Certains utilisateurs trouvent commode de commencer une recherche d'information dans
Access, et de la terminer dans Excel. Il faut dire que la plupart des utilisateurs sont plus à
l'aise dans le second logiciel que dans le premier. Mais faut également reconnaître que la mise
en forme finale des données avant impression est plus facile à réaliser dans une feuille de
calcul d'Excel que dans un état d'Access.
L'exportation des données des BDD vers le web prend de plus en plus
d'importance. On distingue :
les pages web statiques, c'est à dire générées d'abord depuis une base de données,
puis mises en ligne sur un serveur web ;
les pages web dynamiques. Elles sont générées à la volée par un script côté serveur à
partir de données résidant dans une base de données, juste avant d'être envoyées au client
internaute.
Les deux types de pages ont leurs mérites et leurs inconvénients, et leurs
applications sont distinctes ; nous n'entrerons pas dans une discussion à ce sujet. Précisons
qu'Access ne permet pas de créer des pages dynamiques, et que son mode de création de
pages statiques est fort médiocre. L'opération n'est pas paramétrable, et le code HTML obtenu
n'est pas fameux. Pour faire communiquer une BDD (gérée sous Access) et le web, on utilise
généralement du logiciel tierce partie.
6 - Conclusion
Les échanges d'information (données et objets) entre BDD sont plus ou moins
faciles suivant les cas envisagés. De ce point de vue, Access est un SGBD relativement
ouvert, qui reconnaît plusieurs formats.
Les échanges de données et d'objets entre bases gérées par Access sont très aisés.
L'importation de données en provenance de fichiers texte ou HTML est bien gérée par
Access. L'exportation -- en particulier vers le web -- est médiocre, c'est un point faible de ce
SGBD.
© TIBB imbwangatroptard@[Link]
49
SQL
plusieurs instructions. En clair, une seule macro-instruction entraîne l'exécution d'un grand
nombre de tâches élémentaires.
Cependant, les macros ne sont pas utilisées pour faire de la programmation à
proprement parler, et ce pour les raisons suivantes :
la notion de variable leur fait défaut. Exemple : si une macro ouvre un fichier, et si
vous changez le nom du fichier, vous devez corriger la macro en conséquence ;
le branchement conditionnel est soit absent, soit très sommaire. Les actions d'une
macro s'exécutent séquentiellement. Tout au plus peut-on rendre une exécution
conditionnelle ;
le traitement des erreurs n'existe pas. Si une macro provoque une erreur d'exécution,
elle affiche un message et s'arrête.
Le véritable usage des macros, c'est l'automatisation des tâches répétitives, que
l'on utilise Access ou tout autre logiciel. Une telle automatisation présente deux avantages
importants, qui justifient généralement le temps passé à écrire les macros :
elle fait gagner du temps ;
elle diminue le risque d'erreurs.
Bien entendu, il ne faut automatiser que des opérations qui ont été rodées
manuellement, et qui sont bien au point. Il s'agit là d'une remarque de bon sens, qui déborde
largement le cadre des macros.
Les macros sont très spécifiques d'un logiciel donné ; les macros d'Access, par
exemple, sont très différentes de celles d'Excel. On trouve des macros dans de nombreux
logiciels, et même dans certains systèmes d'exploitation. Leur conception, leur facilité
d'usage, et les services qu'elles rendent, varient beaucoup d'un logiciel à l'autre.
Des macros peuvent regrouper toutes les actions répétitives associées à ces
opérations, et c'est là leur principale application.
Une application secondaire des macros consiste à associer des actions à des
boutons. Tous les utilisateurs de SGBD qui aiment le décorum parsèment leurs formulaires et
leurs menus de boutons. Lorsqu'on examine la liste des actions que permettent les macros
d'Access, on voit clairement qu'un certain nombre d'entre elles ont été créées dans ce but.
C'est un aspect des macros que nous signalons, mais que nous n'approfondirons pas.
On notera que les professionnels qui utilisent Access pour développer des
applications, se servent généralement assez peu des macros. Ils préfèrent utiliser VBA (Visual
Basic for Applications), une extension du langage Visual Basic qui permet de manipuler les
© TIBB imbwangatroptard@[Link]
50
SQL
objets d'Access, sans présenter les limitations des macros. Les utilisateurs non professionnels
se trouvent plutôt dans la situation inverse, parce qu'apprendre à se servir des macros est
beaucoup -- beaucoup -- plus rapide que se familiariser avec VBA. C'est la raison pour
laquelle nous avons inclus ce chapitre dans le présent tutoriel dédié aux bases de données
relationnelles.
Comme pour les autres chapitres, nous utiliserons le SGBD Access comme
support pratique de ce tutoriel (ou tutorial, ou cours en ligne). Nous n'examinerons pas toutes
les actions utilisables pour créer une macro, car il en existe une bonne cinquantaine. Notre but
sera plutôt de montrer ce que l'on peut faire, et de souligner ce que l'on ne peut pas faire, avec
les macros. Notre choix comporte fatalement une forte part d'arbitraire, si bien que nous
acceptons par avance toutes les remarques et suggestions.
© TIBB imbwangatroptard@[Link]
51
SQL
Dans la grille de création de macro, choisissez l'action "BoîteMsg". Cette fois,
des arguments sont nécessaires :
Message : vous pouvez écrire le texte du message qui sera affiché. Mais vous pouvez
aussi créer une expression qui effectuera des calculs ou opérera sur des chaînes, à condition
de la faire précéder du signe égal. Par exemple, saisissez "=Date()" (sans les guillemets), pour
afficher la date du jour. Ce sera toujours plus intéressant que d'afficher "Hello folks", comme
on le fait au début des cours de programmation ;
Bip : précisez par "Oui" ou par "Non" si vous voulez que l'affichage du message
s'accompagne d'un bip sonore ;
Type : définit l'image qui illustrera la boite de message. Pour la date du jour,
"Information" fera l'affaire ;
Titre : définit le texte qui s'affiche en haut de la boite de dialogue. Par exemple,
"Nous sommes le :" convient. Notez que l'argument "Titre" peut être traité comme l'argument
"Message".
Il ne vous reste plus qu'à appuyer sur le bouton "Exécuter". Le système vous
demande d'enregistrer d'abord la macro, et vous propose le nom "Macro1", ce qui peut
convenir à votre première macro (pour une macro utile, le nom du service rendu serait plus
avisé). Merveille ! cela marche (enfin, nous l'espérons), et vous obtenez le message suivant, à
la date près :
5 - L'importation de données
Nous avons montré au chapitre précédent comment importer dans Access les
données d'un fichier texte. Si une telle opération est répétée régulièrement, on gagnera du
temps en l'automatisant à l'aide d'une macro.
Nous avons vu que l'on pouvait enregistrer le format personnalisé d'importation
(boutons "Avancé...", puis "Enregistrer sous..."). Ce format contient la plupart des réponses
© TIBB imbwangatroptard@[Link]
52
SQL
aux questions posées par l'assistant. On peut le réutiliser à chaque importation manuelle, et
nous allons nous en servir pour créer la macro d'importation.
L'action correspondant à une importation de fichier texte s'appelle
"TransférerTexte" et possède sept arguments, dont les cinq premiers seulement nous
concernent :
Type transfert : nous permet de préciser "délimité" ;
Format : dans la liste déroulante, nous retrouvons le format d'importation que nous
avons créé lors de l'importation manuelle ;
Nom table : nous précisons la table dans laquelle les données seront introduites. Si
cette table existe déjà, les données seront rajoutées à celles déjà présentes ;
Nom fichier : le chemin complet d'accès au fichier doit être inscrit ici (exemple : C:\
Documents and Settings\Administrateur\Bureau\Tutoriel\[Link]) ;
Contient noms de champs : la réponse est "Oui" quand la première ligne du fichier
texte contient les noms des champs et que l'on veut les conserver. Présentement, la réponse
est "Non".
La macro est prête, il ne reste plus qu'à l'enregistrer, puis à l'exécuter. Bien
entendu, la macro n'est réutilisable que si les noms de fichier, de table, et de format ne
changent pas : nous butons là sur le fait que la notion de variable n'existe pas dans les macros.
En reprenant tel quel l'exemple du chapitre précédent, nous obtenons le résultat déjà cité :
Dans la version 2002 d'Access, l'importation via une macro est une opération
rapide (ce n'était pas le cas des versions plus anciennes). A titre d'exemple : sur un PC de
milieu de gamme, un fichier texte de 10 Mo, contenant 50.000 lignes de 10 champs chacune
(20 octets d'information en moyenne par champ), s'importe en moins de 10 secondes.
6 - La suppression d'enregistrements
Nous allons maintenant écrire une macro qui efface les trois premières lignes de
la table précédente. Rappelons-nous qu'une macro ne fait qu'enchaîner de manière
automatique des opérations qui sinon seraient effectuées une à une par l'opérateur. Pour
supprimer manuellement les trois premières lignes de la table, nous procédons de la manière
suivante :
nous ouvrons la table, car il est impossible de travailler dans une table fermée ;
nous plaçons le curseur sur la première ligne ;
© TIBB imbwangatroptard@[Link]
53
SQL
dans le menu "Édition" nous choisissons "Supprimer l'enregistrement". Nous
acquittons le message, l'enregistrement disparaît, et le curseur passe automatiquement sur la
ligne suivante ;
nous répétons l'opération une deuxième fois ;
nous répétons l'opération une troisième fois.
Nous allons, dans la macro, retrouver à peu de choses près les mêmes étapes. Les
actions utilisées sont les suivantes :
OuvrirTable. Cette action ouvre effectivement la table (si elle n'est pas déjà ouverte).
Il y a trois arguments. Le premier "Nom table" permet de choisir le nom de la table dans la
liste déroulante. Pour le second ("Affichage"), la bonne valeur est "Feuille de données". Pour
le troisième ("Mode données"), le bon choix est "Modification" ;
AtteindreEnregistrement. Cette action place le curseur sur une ligne spécifiée de la
table. Il y a quatre arguments, mais seuls les trois premiers nous concernent. La réponse à
"Type objet" est "Table", la réponse à "Nom objet" est le nom de la table, et la réponse à
"Enregistrement" est "Premier" de telle sorte que le curseur se place sur la première ligne. Si
la table n'avait pas été ouverte par l'action précédente, cette action arrêterait la macro avec
affichage d'un message d'erreur ;
Avertissements. En fixant l'argument "Avertissements actifs" à "Non", nous rendons
la macro silencieuse. Aucune confirmation ne nous sera demandée avant la suppression des
lignes. Seuls les messages inévitables (ex : message d'erreur) sont encore émis. Le but de ce
silence est de gagner du temps, une macro étant faite pour aller vite ;
ExécuterCommande. Pour l'unique argument "Commande" il faut choisir
"SupprimerEnregistrement". Cette action supprime la première ligne de la table. La deuxième
ligne devient la première, et le curseur s'y trouve placé ;
ExécuterCommande. Pour l'unique argument "Commande" il faut choisir
"SupprimerEnregistrement". Cette action supprime la première (ex-seconde) ligne de la table.
La deuxième (ex-troisième) ligne devient la première, et le curseur s'y trouve placé ;
ExécuterCommande. Pour l'unique argument "Commande" il faut choisir
"SupprimerEnregistrement". Cette action supprime la première (ex-troisième) ligne de la
table. La deuxième (ex-quatrième) ligne devient la première, et le curseur s'y trouve placé ;
ArrêtMacro. Cette action est facultative. Lorsqu'il n'y a plus d'actions à exécuter, la
macro s'arrête et les avertissements redeviennent actifs.
© TIBB imbwangatroptard@[Link]
54
SQL
La macro que nous venons de créer comporte sept actions. Chaque action
correspond en gros à une instruction en VBA. Vous voyez ainsi d'où provient le terme de
macro-instruction.
On peut regrouper les deux macros précédentes, si bien que la suppression des
trois premières lignes de la table suit immédiatement l'importation des données.
La facilité d'écriture directe dans les tables peut varier de très pratique à
parfaitement impraticable suivant les cas. Un formulaire peut rendre la saisie de certaines
informations plus facile, principalement dans les SGBD qui, au contraire d'Access, n'affichent
pas les sous-feuilles de données. Enfin, les formulaires permettent l'ajout de boutons, menus,
etc. qui donnent à l'application un aspect très "fini". Les SSII (sociétés de service en
informatique) soignent donc les formulaires pour donner la meilleure impression possible à
leur client -- surtout si ce dernier n'est pas capable de juger sur autre chose que la
présentation.
Certaines bases de données sont principalement alimentées en données par
importation des données : le formulaire ne sert alors plus à rien. C'est, par exemple, le cas
des magasins à grande surface, qui alimentent leur BDD directement et en temps réel depuis
les caisses enregistreuses. C'est aussi le cas des sites web qui déversent quotidiennement leur
fichier journal dans la BDD qui sert au suivi du site et à la mesure d'audience. C'est encore le
cas de tous ceux qui font de l'acquisition de données via des capteurs couplés à des
ordinateurs, etc.
© TIBB imbwangatroptard@[Link]
55
SQL
Accessoirement, le formulaire sert aussi d'outil de visualisation, c'est à dire de
consultation du contenu de la base à l'écran. On reproche parfois au formulaire de montrer les
enregistrements un par un, alors qu'une table en montre un grand nombre à la fois, mais on
peut concevoir le formulaire de telle sorte que sa présentation soit très proche de celle d'une
table.
Cette discussion peut en fait se résumer ainsi :
lorsque la BDD est utilisée par des personnes très diverses sans expérience
particulière en matière de SGBD, ou lorsque l'accès aux tables est interdit aux utilisateurs, ou
lorsque la saisie directe dans les tables est malaisée, les formulaires constituent un passage
obligé ;
lorsque la BDD est utilisée par un petit groupe de professionnels formés à l'usage des
SGBD, ou lorsque les données sont importées au lieu d'être saisies, les formulaires
constituent un simple habillage de la BDD et n'ont guère d'utilité.
Pour travailler sérieusement, nous créons un index sans doublon sur les champs
Nom+Prénom dans "Personnes", et sur les champs "commune+code postal dans
"Communes". Nous interdisons de plus le Null et la chaîne vide dans tous les champs sauf
"Adresse". Le champ "code_commune" de la table "Communes" est du type NuméroAuto.
Créons, pour commencer, un formulaire simple qui nous permette de saisir les
noms des communes et les codes postaux correspondants. Dans la fenêtre "Base de données",
© TIBB imbwangatroptard@[Link]
56
SQL
nous sélectionnons (colonne de gauche) l'objet "Formulaires". Nous double-cliquons sur
"Créer un formulaire à l'aide de l'Assistant" et nous répondons aux demandes de ce dernier :
d'abord, nous sélectionnons la table "Communes". Les champs disponibles s'affichent
(code_commune, commune, code postal), et nous sélectionnons les deux derniers. En effet le
code, qui sert à faire fonctionner la mécanique relationnelle, est implémenté par le système
lui-même (type de données NuméroAuto) ;
ensuite, nous choisissons une disposition -- "Colonne simple" par exemple ;
puis nous choisissons l'un des styles proposés ;
enfin nous nommons le formulaire "Formulaire des communes", et nous cliquons sur
"Terminer".
Le formulaire est constitué d'étiquettes (les noms des champs dans la table) et de
contrôles correspondant aux champs de la table. Lorsqu'ils sont directement dérivés de la
table, les contrôles sont appelés "contrôles dépendants", ou encore "champs". La table à partir
de laquelle est construit le formulaire est la table sous-jacente.
Nous constatons d'abord que nous pouvons examiner le contenu de la table
"Communes" enregistrement par enregistrement, le formulaire jouant alors son rôle d'outil de
visualisation. Certes, l'aspect est plus joli que celui de la table, mais cette dernière présente
l'avantage de nous donner une vue globale des informations. Si nous avions choisi la
disposition "Tabulaire", nous aurions obtenu une présentation par lignes plus proche de la
table sous-jacente. La disposition "Feuille de données", quant à elle, fournit une présentation
pratiquement identique à celle de la table sous-jacente.
Nous constatons ensuite que nous pouvons nous placer sur la première ligne vide
de la table sous-jacente, et saisir des données (noms et prénoms des personnes). Ces données
sont automatiquement introduites dans la table sous-jacente, comme nous pouvons le
constater en fermant le formulaire et en ouvrant la table. Le formulaire joue alors son rôle
d'outil de saisie des données. Mais les problèmes de synchronisation que nous avons déjà
rencontrés demeurent : si nous laissons la table sous-jacente ouverte, nous constatons que les
données saisies dans le formulaire n'y apparaissent pas. On peut fermer, puis rouvrir la table
sous-jacente, pour que les nouvelles données s'y trouvent inscrites, mais il est plus simple de
rendre la table active, de cliquer dans le menu sur "Enregistrements", puis sur "Afficher tous
les enregistrements". La table se complète immédiatement.
Notons que le formulaire nous présente les informations dans l'ordre où elles se
trouvent dans la table sous-jacente. Pour faire en sorte que les informations apparaissent
triées, nous disposons de plusieurs méthodes :
nous pouvons effectuer une requête de sélection simple sur la table (en sélectionnant
tous les champs, en triant d'abord sur le nom et ensuite sur le prénom), puis créer le
© TIBB imbwangatroptard@[Link]
57
SQL
formulaire à partir de cette requête. Toutes les saisies que nous effectuons dans ce nouveau
formulaire sont automatiquement transmises à la table "Personnes", au travers (si l'on peut
dire) de la requête de tri ;
si un tri simple nous convient, nous plaçons le curseur dans le champ désiré du
formulaire, puis nous cliquons sur l'icône du tri ;
pour effectuer un tri multiple, nous cliquons dans le menu sur "Enregistrements", puis
sur "Filtrer", puis sur "Filtre/tri avancé..." et nous intervenons dans la grille qui s'affiche.
La mise en forme d'un formulaire, avec ses très nombreuses possibilités, fera
l'objet d'une annexe (décembre 2002). Nous reviendrons plus loin sur certains usages
© TIBB imbwangatroptard@[Link]
58
SQL
particuliers de la boite à outils. Voici ce que devient la figure précédente après un léger lifting
:
4 - Le perfectionnement du formulaire
Pour modifier les propriétés d'un formulaire, il faut ouvrir sa feuille de propriétés
de la manière suivante :
sélectionner le formulaire ;
cliquer sur l'icône "Modifier" ;
cliquer sur l'icône "Propriétés" ou double-cliquer sur le carré noir qui se trouve en
haut et à gauche de la fenêtre du formulaire ;
sélectionner l'onglet "Données", qui donne accès à diverses propriétés du formulaire.
Dans le formulaire tel qu'il est, nous pouvons non seulement saisir de nouvelles
données, mais aussi modifier ou supprimer des données existantes. Cette possibilité peut être
fort dangereuse, et nous pouvons la supprimer en basculant la propriété "Modif autorisée" de
"Oui" à "Non". En revenant en mode formulaire, nous constatons que désormais, les données
enregistrées (par fermeture du formulaire) ne peuvent plus être modifiées. Cette interdiction
est très gênante en cas d'erreur de saisie, mais elle ne s'étend pas à la table sous-jacente.
Nous pouvons aller plus loin, et cacher complètement les enregistrements déjà
saisis. Les enregistrements nouvellement saisis seront cachés à leur tour dès que nous
refermerons le formulaire. Pour ce faire, nous basculons la propriété "Entrée données" de
"Oui" à "Non". En revenant en mode formulaire, nous constatons qu'aucune donnée ne
s'affiche. Nous pouvons, par contre, saisir de nouvelles données.
Nous pouvons aussi faire en sorte que le formulaire ne permette pas la
modification des données, c'est à dire qu'il serve uniquement de dispositif de visualisation.
Pour ce faire, nous basculons la propriété "Ajout autorisé" de "Oui" à "Non", puis nous
revenons au mode formulaire. Nous pouvons ainsi donner à un utilisateur la possibilité de
consulter la base, mais sans pouvoir en modifier le contenu.
Recréons le formulaire des communes en incluant le champ "code_commune".
Nous constatons que nous pouvons introduire le curseur dans ce champ, mais que nous ne
pouvons pas le modifier. Le type de données est NuméroAuto, et seul le SGBD peut écrire
dans ce champ. Dans le formulaire, cette propriété est héritée de la table sous-jacente. Pour ne
pas agacer la personne qui utilise le formulaire, nous pouvons faire en sorte que le curseur ne
passe plus dans le champ "code_commune". Plusieurs solutions s'offrent à nous.
Pour modifier les propriétés d'un contrôle ou d'une étiquette, nous pouvons faire
apparaître la feuille de données comme ci-dessus, et sélectionner l'objet dans la liste
déroulante qui se trouve tout en haut. Nous pouvons aussi sélectionner l'objet en mode
création , effectuer un clic droit, et choisir "Propriétés".
Sélectionnons l'onglet "Autres", et basculons la propriété "Arrêt tabulation" de
"Oui" à "Non". Quand nous revenons au mode formulaire, nous constatons que le curseur ne
© TIBB imbwangatroptard@[Link]
59
SQL
peut plus être placé dans le champ "code_commune", bien que la valeur de ce dernier
continue à s'afficher.
Nous pouvons aussi sélectionner l'onglet "Donnée", et basculer la propriété
"Activé" de "Oui" à "Non" (la propriété "Verouillé" étant sur "Non"). Quand nous revenons
au mode formulaire, nous constatons que le contrôle "code_commune" et son étiquette sont
grisés, comme lorsqu'une fonction n'est pas disponible dans un menu. De plus, le curseur ne
pénètre plus dans le champ. La figure suivante illustre cette situation :
Basculer la propriété "Verrouillé" à "Oui" (la propriété "Activé" étant sur "Oui")
a pour conséquence d'empêcher la modification du contenu du champ, sans en modifier
l'aspect et sans empêcher le curseur d'y pénétrer. Cela ne nous est d'aucune utilité dans le cas
présent, puisque le champ "code_commune" hérite déjà de cette propriété de par son type de
données NuméroAuto.
Pour consulter la suite, qui traite des formulaires basés sur deux tables, cliquez
sur la flèche droite ci-dessous.
Dans la table "Communes", qui sert de liste, nous avons déclaré nulle la largeur
de la colonne "code_commune". Comme pour une table, c'est alors le nom de la commune qui
s'affiche à la place du code. Nous devrions donc modifier l'étiquette, en remplaçant
"Code_commune" par "Commune", afin que l'utilisateur du formulaire ne soit pas troublé.
© TIBB imbwangatroptard@[Link]
60
SQL
© TIBB imbwangatroptard@[Link]
61
SQL
2 - Le formulaire avec liste indépendante
Le logiciel Access nous permet de créer une liste indépendante, contenant par exemple les
noms et prénom déjà saisis. Pour ce faire, nous ouvrons le formulaire en mode création, puis
nous agrandissons la zone d'en-tête pour y placer la liste. Si la boite à outils n'est pas
apparente, nous cliquons sur "Affichage", puis "Boite à outils" (nous pouvons aussi cliquer
sur l'icône ). Dans cette boite, nous activons l'icône "Assistants contrôle". Comme son
3 - Le formulaire basé sur deux tables
L'assistant permet de créer un formulaire basé sur plusieurs tables. Il suffit de
répéter l'opération de saisie des champs pour les tables considérées. Réalisons l'expérience à
l'aide des tables "Personnes" et "Communes". La procédure est la suivante :
nous sélectionnons la table "Personnes", et nous introduisons tous les champs
correspondants ;
nous sélectionnons la table "Commune", et nous sélectionnons le champ "Code
postal". Il est inutile que nous sélectionnions le champ "Code _commune", puisque nous
l'avons déjà pris dans la table "Personnes". Il est également inutile que nous sélectionnions le
champ "Commune", puisque le nom de la commune s'affichera dans le contrôle
"Code_commune", comme nous l'avons vu dans le paragraphe précédent ;
l'assistant nous demande alors si nous souhaitons afficher les données "par
Communes" ou "par Personnes". Nous choisissons la deuxième option, et nous voyons que
cela nous conduit à un formulaire unique. Nous ferons l'essai de la première option dans le
paragraphe suivant ;
nous choisissons la disposition et le style, nous renommons le formulaire, et nous
examinons le résultat, qui est représenté sur la figure ci-dessous, après un peu de mise en
forme.
nom l'indique, cette icône active un certain nombre d'assistants relatifs à la création de
contrôles.
© TIBB imbwangatroptard@[Link]
62
SQL
Nous cliquons ensuite sur l'icône "Zone de liste déroulante", puis à l'endroit
choisi pour implanter la liste. La boite de dialogue "Assistant de zone de liste déroulante"
s'ouvre. Nous dialoguons ainsi avec l'assistant :
nous choisissons la troisième option "Rechercher un enregistrement dans mon
formulaire basé sur la valeur que j'ai sélectionnée..." ;
nous sélectionnons ensuite le nom et le prénom ;
nous réglons graphiquement la largeur des colonnes ;
nous baptisons l'étiquette "Liste des personnes", et nous cliquons sur terminer ;
nous ajustons graphiquement la position de la liste (lorqu'une petite main noire
apparait) ;
nous réglons les détails de présentation, puis nous basculons en cliquant sur l'icône
"Ouvrir" pour observer le résultat.
Si nous avons pris la précaution de baser le formulaire sur une requête qui trie la
table "Table01", la liste indépendante que nous venons de créer est triée par ordre
alphabétique. Nous pouvons donc vérifier rapidement si le nom d'une personne donnée a déjà
été saisi. De plus, si nous sélectionnons un nom dans cette liste, les informations
correspondantes s'affichent immédiatement, comme le montre la figure ci-dessous. Par contre,
le fait de changer d'enregistrement n'a pas d'influence sur la liste indépendante.
© TIBB imbwangatroptard@[Link]
63
SQL
Nous obtenons ainsi un formulaire principal dans lequel nous pouvons saisir des
noms de communes avec leur code postal,et les utiliser dans le sous-formulaire associé. La
figure ci-dessous illustre le résultat obtenu :
5 - Conclusion
Ce chapitre, étalé sur deux pages web, donne un aperçu de l'objet formulaire
dans les bases de données. Il ne prétend pas, loin de là, épuiser le sujet, qui est fort vaste. A un
formulaire on peut associer des boutons, de la programmation événementielle, etc. On peut
modifier la présentation, l'étaler sur plusieurs pages, créer des onglets, etc. Du point de vue de
l'auteur de ces lignes, tout ceci ressemble un peu à du décorum, mais... à chacun ses goûts !
En fait, ce n'est pas tellement le formulaire que nous critiquons, mais l'usage qui
en est fait. Les administrateurs de BDD font presque toujours en sorte que les utilisateurs ne
puissent voir les données qu'à travers les formulaires. Privés de tables, les utilisateurs ne
peuvent pas créer de requêtes, et la base de données de l'entreprise perd pour eux une grosse
© TIBB imbwangatroptard@[Link]
64
SQL
part de son intérêt. Se doter d'un outil coûteux (très coûteux, même, dans la plupart des cas),
et en limiter le plus possible l'usage, quel paradoxe !
© TIBB imbwangatroptard@[Link]