On peut trouver ce didacticiel SQL à http://w3.one.net/~jhoffman/sqltut.htm
Pour les commentaires ou suggestions, envoyer un courrier électronique à jhoffman@one.net
Vous pouvez également souhaiter jeter un oeil à http://w3.one.net/~jhoffman/index.html
John Hoffman suggère de visiter les sites suivants :
http://www.contrib.andrew.cmu.edu/~shadow/sql.htmlRéférence SQL
http://www.inquiry.com/techtips/thesqlpro/Demandez le Pro. de SQL
http://www.inquiry.com/techtips/thesqlpro/usefulsites.htmlSites utiles au Pro. du SGBD Relationnel SQL
http://infoweb.magi.com/~steve/develop.htmlLes Sites de sources du programmeur SGBD
http://info.itu.ch/special/wwwfiles Allez-y et regardez le fichier comp_db.html
http://www.compapp.dcu.ie/databases/f017.htmlIngrédients pour SGBD
http://www.stars.com/Tutorial/CGI/Création Web
http://wfn-shop.princeton.edu/cgi-bin/foldocDictionnaire d'Informatique
http://www-ccs.cs.umass.edu/db.htmlDBMS Lab/Liens
SQL FAQ http://epoch.CS.Berkeley.EDU:8000/sequoia/dba/montage/FAQ Allez-y et regardez le fichier SQL_TOC.html
http://chaos.mur.csu.edu.au/itc125/cgi/sqldb.htmlSGBD SQL
http://www.it.rit.edu/~wjs/IT/199602/icsa720/icsa720postings.htmlPage de Conception de Bases de Données RIT
http://www.pcslink.com/~ej/dbweb.htmlSite de liens vers des Bases de Données http://www.eng.uc.edu/~jtilley/tutorial.htmlDidacticiels de programmation sur le Web
http://www.ndev.com/ndc2/support/resources.htpRessources pour le Développement
http://ashok.pair.com/sql.htmListe de Requêtes
http://jazz.external.hp.com/training/sqltables/main.htmlIMAGE SQL Diverses
http://www.eit.com/web/netservices.htmlListe de Ressources Internet
Voici, ci-dessous, un extrait de la page d'accueil du didacticiel SQL.
Introduction au Langage de Requête Structuré
Version 3.31
Cette page contient un didacticiel du Langage de Requête Structuré( Structured
Query Language, également connu sous le nom de SQL). Ce didacticiel constitue
une nouveauté sur le World Wide Web, car c'est le premier didacticiel SQL
complet disponible sur l'Internet. SQL permet l'accès aux données dans les
systèmes de gestion de bases de données relationnels tels que Oracle,
Sybase, Informix, Microsoft SQL Server, Access, et autres en permettant aux
utilisateurs de décrire les données qu'ils désirent obtenir. SQL permet aussi
aux utilisateurs de définir l'organisation des données dans la base et de les
manipuler. Le but de cette page est de décrire l'utilisation de SQL, et de
donner des exemples. C'est le langage ANSI SQL, ou standard SQL, qui sera
utilisé dans ce document. Il ne sera pas question ici des fonctionnalités
spécifiques à un SGBD particulier, qui seront traitées dans la section "SQL
non-standard". Nous vous recommandons d'imprimer cette page afin de pouvoir
vous référer facilement aux différents exemples.
----------------------------------------------------------------------------
Table des matières
Principes fondamentaux de l'instruction SELECT
Sélection Conditionnelle
Opérateurs Relationnels
Conditions Composées
IN & BETWEEN
Utilisation de LIKE
Jointures
Clés
Réalisation d'une Jointure
Elimination des Doubles
Alias & In/Sous-requêtes
Fonctions d'Agrégation
Vues
Création de Nouvelles Tables
Modification des Tables
Ajout de Données
Suppression de Données
Mise à Jour des Données
Index
GROUP BY & HAVING
Sous-requêtes Supplémentaires
EXISTS & ALL
UNION & Jointures Externes
SQL Intégré
Questions Courantes sur SQL
SQL Non-standard
Résumé de la Syntaxe
Liens Importants
----------------------------------------------------------------------------
Principes fondamentaux de l'instruction SELECT
Dans une base de données relationnelle, les données sont stockées dans des
tables. Par exemple, une table pourrait mettre en relation le Numéro de
Sécurité Sociale, le Nom et l'Adresse:
TableAdresseEmploye
NSS Prenom Nom Addresse Ville Etat
512687458Joe Smith 83 First Street Howard Ohio
758420012Mary Scott 842 Vine Ave. LosantivilleOhio
102254896Sam Jones 33 Elm St. Paris New York
876512563Sarah Ackerman 440 U.S. 110 Upton Michigan
Maintenant, supposons que nous voulions obtenir l'adresse de chaque employé.
On utilisera SELECT, comme ceci :
SELECT Prenom, Nom, Adresse, Ville, Etat
FROM TableAdresseEmploye;
Voici le résultat de l'interrogation de notre base de données :
Prenom Nom Adresse Ville Etat
Joe Smith 83 First Street Howard Ohio
Mary Scott 842 Vine Ave. Losantiville Ohio
Sam Jones 33 Elm St. Paris New York
Sarah Ackerman 440 U.S. 110 Upton Michigan
Explication de ce que l'on vient de faire : on vient de rechercher dans toutes
les données de la table TableAdresseEmploye les colonnes nommées Prenom, Nom,
Adresse, Ville et Etat. Noter que les noms de colonnes et les noms de tables
sont sans espaces... ils doivent être saisis en un seul mot; et que
l'instruction se termine par un point-virgule (;). La forme générale d'une
instruction SELECT, qui permet de retrouver toutes les lignes d'une table
est :
SELECT NomColonne, NomColonne, ...
FROM NomTable;
Pour obtenir toutes les colonnes d'une table sans avoir à taper tous les noms
de colonne, utiliser :
SELECT * FROM NomTable;
Chaque Système de Gestion de Base de Données (SGBD) et chaque logiciel de
base de données utilisent différentes méthodes pour se connecter à la base
de donnée et pour entrer les instructions SQL; consultez le "guru" de votre
ordinateur pour qu'il vous aide à vous connecter de façon à pouvoir utiliser
SQL.
----------------------------------------------------------------------------
Sélection Conditionnelle
Pour étudier plus avant l'instruction SELECT , jetons un oeil à un nouvel exemple de table
(exemple uniquement hypothétique) :
EmployeeStatisticsTable
EmployeeIDNo Salary Benefits Position
010 75000 15000 Manager
105 65000 15000 Manager
152 60000 15000 Manager
215 60000 12500 Manager
244 50000 12000 Staff
300 45000 10000 Staff
335 40000 10000 Staff
400 32000 7500 Entry-Level
441 28000 7500 Entry-Level
----------------------------------------------------------------------------
Opérateurs Relationnels
Il y a six Opérateurs Relationnels en SQL, et, après les avoir présentés,
nous verrons comment les utiliser :
= Egal
<> or !=
(voir le manuel) Différent
< Plus Petit Que
> Plus Grand Que
<= Plus Petit Que ou Egal à
>= Plus Grand Que ou Egal à
La clause WHERE est utilisée pour spécifier que l'on affichera seulement
certaines ligne de la table, selon un critère définit par cette clause WHERE.
Ce sera plus clair en prenant une paire d'exemples.
Si l'on désire voir les numéros d'identification des employés (EMPLOYEEIDNO)
dont le salaire est égal ou supérieur à 50 000, on utilisera la requête
suivante :
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE SALARY >= 50000;
Noter que le symbole >= (plus grand que ou égal à) est utilisé, puisque l'on
désire voir tout ceux qui gagnent plus de 50 000, ou 50 000, sur la même
liste. On aura l'affichage :
EMPLOYEEIDNO
------------
010
105
152
215
244
La description de WHERE, SALARY >= 50000, est appelée une condition. On pourrait
effectuer le même traitement sur des colonnes de texte :
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION = 'Manager';
Ceci entraînera l'affichage des Numéros d'Identification de tous les Managers.
En général, avec les colonnes contenant du texte, n'utiliser que égal à ou
différent de, et assurez vous que tout texte apparaissant dans l'instruction
est entouré d'apostrophes (').
----------------------------------------------------------------------------
Conditions plus complexes: Conditions Composées
L'opérateur AND (ET) combine deux ou plusieurs conditions et n'affiche une
ligne que si cette ligne satisfait TOUTES les conditions requises (i.e. où
toutes les conditions sont réalisées). Par exemple, pour afficher tout le
personnel gagnant plus 40 000, écrire :
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE SALARY > 40000 AND POSITION = 'Staff';
L'opérateur OR (OU) combine deux ou plusieurs conditions mais retourne cette
ligne si N'IMPORTE LAQUELLE des conditions requises est remplie. Pour
visualiser tous ceux qui gagnent moins de 40 000 ou qui reçoivent moins de 10
000 en participation aux bénéfices, utilisez la requête suivante :
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE SALARY < 40000 OR BENEFITS < 10000;
Les opérateurs AND et OR peuvent être combinés, par exemple :
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION = 'Manager' AND SALARY > 60000 OR BENEFITS > 12000;
En premier lieu, SQL recherche les lignes pour lesquelles la valeur de la
colonne salaire est supérieure à 60 000 et celle de position est égale à
Manager, puis, à partir de cette liste de lignes, SQL recherche alors celles
qui satisfont à la condition AND (ET) précédente ou à la condition spécifiant
que la colonne Indemnités est supérieure à 12 000. En conséquence, SQL n'affiche
seulement que cette seconde liste de lignes, en gardant à l'esprit que tous ceux
dont les Indemnités sont supérieures à 12 000 en feront partie puisque l'opérateur
OR (OU) inclue la ligne si l'une des conditions est vérifiée. Notez en passant
que l'opération AND (ET) est effectuée en premier.
Pour généraliser ce processus, SQL effectue l(es) opération(s) AND pour déterminer
les lignes ou l(es) opération(s) AND sont vérifiées (souvenez-vous bien : toutes
les conditions sont vérifiées), puis ces résultats sont utilisés pour tester les
conditions OR, et, ne seront affichées que les lignes où les conditions requises
par l'opérateur OR seront vérifiées.
Pour que les OR's soient effectués avant les AND's, par exemple si vous vouliez voir
une liste des employés dont le salaire est élevé (>50 000) OU bénéficiant d'indemnités
importantes (>10 000), ET qui soient cadres, utilisez des parenthèses :
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION = 'Manager' AND (SALARY > 50000 OR BENEFIT > 10000);
----------------------------------------------------------------------------
IN et BETWEEN
Une méthode plus facile pour utiliser les conditions composées consiste à utiliser
IN ou BETWEEN. Par exemple, si vous désirez une liste des cadres et du personnel :
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION IN ('Manager', 'Staff');
ou une liste de ceux dont le salaire est supérieur ou égal à 30 000, mais inférieur
ou égal à 50 000, utilisez:
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE SALARY BETWEEN 30000 AND 50000;
Pour obtenir la liste de ceux qui n'entrent pas dans ces critères, essayez :
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE SALARY NOT BETWEEN 30000 AND 50000;
De la même façon, NOT IN donne la liste de toutes les lignes exclues de la liste
obtenue par l'opérateur IN.
----------------------------------------------------------------------------
Utilisation de LIKE
Regardons la table EmployeeStatisticsTable, et disons que l'on veut voir tous les
gens dont le nom commence par "L"; essayons :
SELECT EMPLOYEEIDNO
FROM EMPLOYEEADDRESSTABLE
WHERE LASTNAME LIKE 'L%';
Le signe pourcentage (%) est utilisé pour représenter n'importe quel caractère
possible (nombre, lettre, ou signe de ponctuation) ou ensemble de caractères
qui peut apparaître après le "L". Pour trouver les gens dont le Nom se termine
avec "L", utiliser '%L', ou si vous désirez le "L" au milieu du mot, essayez
'%L%'. Le symbole '%' peut être utilisé pour n'importe quel caractère, et
dont la position est relative par rapport à des caractères donnés. NOT LIKE
affiche les lignes qui ne correspondent pas à la description donnée. Il y a
d'autres manières d'utiliser LIKE, de même que n'importe lesquelles des
conditions composées dont nous venons de parler, bien que cela dépende du SGBD
que vous utilisez; comme d'habitude, consultez un manuel ou le gestionnaire ou
administrateur de votre système pour en connaître les fonctionnalités, ou
simplement, assurez vous que ce que vous essayer de faire est possible et
autorisé. Cet avertissement est aussi valable pour les fonctionnalités de SQL
exposées ci-dessous. Cette section est donnée à titre d'exemple des requêtes
qui peuvent être écrites en SQL.
----------------------------------------------------------------------------
Jointures
Dans cette section, nous allons parler uniquement des jointures internes et
des equi-jointures, dans la mesure où ce sont les plus utiles. Pour avoir plus
d'informations, voyez les liens sur des sites SQL au bas de cette page.
On suggère qu'une bonne manière de concevoir une base de données implique que
chaque table ne contienne des données qui ne concernent qu'une seule entité,
et que des informations détaillées peuvent être obtenues, dans une base de
données relationnelle, en utilisant des tables supplémentaires et en effectuant
une jointure.
Premièrement, jetons un oeil à ces exemples de tables :
AntiqueOwners
OwnerIDOwnerLastName OwnerFirstName
01 Jones Bill
02 Smith Bob
15 Lawson Patricia
21 Akins Jane
50 Fowler Sam
---------------------------------------------------------
Orders
OwnerIDItemDesired
02 Table
02 Desk
21 Chair
15 Mirror
--------------------------------------
Antiques
SellerIDBuyerID Item
01 50 Bed
02 15 Table
15 02 Chair
21 50 Mirror
50 01 Desk
01 21 Cabinet
02 21 Coffee Table
15 50 Chair
01 15 Jewelry Box
02 21 Pottery
21 02 Bookcase
50 01 Plant Stand
----------------------------------------------------------------------------
Clés
En premier lieu, nous allons parler du concept de clés. Une clé primaire est
une colonne ou en ensemble de colonnes qui identifie de manière unique les
autres données d'une ligne donnée. Par exemple, dans la table AntiqueOwners,
la colonne OwnerID identifie de manière unique cette ligne. Ceci signifie deux
choses: que deux lignes ne peuvent avoir le même OwnerID, et que, même si
deux propriétaires les mêmes noms et prénoms la colonne OwnerID garantit que
ces deux propriétaires ne seront pas confondus l'un avec l'autre, puisque la
colonne OwnerID unique sera utilisée à travers la base de données pour se
référer à un propriétaire, plutôt que son nom.
Une clé externe est une colonne d'une table qui est clé primaire d'une autre
table, ce qui signifie que toutes les données d'une clé externe doivent avoir
des données correspondantes dans l'autre table, où cette colonne est la clé
primaire.
Pour parler SGBD, cette correspondance est connue sous le nom d'intégré
référentielle. Par exemple, dans la table Antiques, BuyerID et SellerID sont
tous les deux des clés externes à la clé primaire de la table AntiqueOwners
(OwnerID; pour les besoins de notre argumentation, on doit d'abord être
référencé dans la table AntiqueOwners avant de pouvoir acheter ou vendre quoi
que ce soit), puisque, dans les deux tables, les colonnes ID sont utilisées
pour identifier les propriétaires, les acheteurs ou les vendeurs, et que
OwnerID est la clé primaire de la table AntiqueOwners. En d'autres termes,
toutes ces données "ID" sont utilisées pour se référer aux propriétaires,
acheteurs et vendeurs sans avoir à utiliser les noms effectifs.
----------------------------------------------------------------------------
Réalisation d'une jointure
Le but de ces clés est ainsi de pouvoir mettre en relation les données à
travers les tables sans avoir à répéter les données dans chaque tables,
--c'est toute la puissance des bases de données relationnelles. Par exemple,
on peut trouver les noms de ceux qui ont acheté une chaise sans avoir à lister
la totalité du nom de l'acheteur dans la table Antiques... vous pouvez trouver
ce nom en mettant en relation ceux qui ont acheté une chaise avec les noms
dans la table AntiqueOwners en utilisant le OwnerID, qui met en relation les
données dans les deux tables. Pour trouver les noms de ceux qui ont acheté
une chaise, utilisez la requête suivante :
SELECT OWNERLASTNAME, OWNERFIRSTNAME
FROM ANTIQUEOWNERS, ANTIQUES
WHERE BUYERID = OWNERID AND ITEM = 'Chair';
Notez ce qui suit au sujet de cette requête... notez que les deux tables mise
en jeux dans cette relation sont listées dans la clause FROM de l'instruction.
Dans la clause WHERE, notez, en premier lieu, que la partie ITEM = 'Chair' de
la clause limite la liste à ceux qui ont acheté (et, dans cet exemple, de ce
fait possèdent) une chaise. En second lieu, notez comment les colonnes ID sont
mises en relation d'une table à la suivante par l'utilisation de la clause
BUYERID = OWNERID. Ne seront listés que les noms de la table AntiqueOwners
dont les ID correspondent à travers les tables et dont l'article acheté est
une chaise (à cause du AND). Parce que la condition de jointure utilisée est
un signe égal, cette jointure est appelée une équi-jointures. le résultat de
cette requête donnera deux noms: Smith, Bob et Fowler, Sam.
La notation avec un point (.) fait référence à l'utilisation du nom de colonne
en suffixe du nom de table pour éviter toute ambiguïté, comme par exemple:
SELECT ANTIQUEOWNERS.OWNERLASTNAME, ANTIQUEOWNERS.OWNERFIRSTNAME
FROM ANTIQUEOWNERS, ANTIQUES
WHERE ANTIQUES.BUYERID = ANTIQUEOWNERS.OWNERID AND ANTIQUES.ITEM = 'Chair';
Cependant, puisque les noms de colonnes sont différents dans chaque table,
cela n'était pas nécessaire.
----------------------------------------------------------------------------
DISTINCT et l'Elimination des Doubles
Disons que vous ne vouliez seulement que la liste des Identificateurs (ID) et
des noms des gens qui ont vendu une antiquité. Evidemment, vous ne désirez
une liste où chaque vendeur n'apparaît qu'une fois--vous ne voulez pas savoir
combien d'antiquités ont été vendues par une personne, mais uniquement le fait
que cette personne en a vendu une (pour les comptages, voir la fonction
d'Agrégation ci-dessous). Cela signifie qu'il vous faudra dire à SQL d'éliminer
les doubles des lignes des ventes, et de ne seulement lister chaque personne
qu'une fois. Pour réaliser cela, utilisez le mot-clé DISTINCT.
Premièrement, vous aurez besoin de faire un équi-jointures sur la table
AntiqueOwners pour obtenir les données concernant le Nom et le Prénom de la
personne. Cependant, gardez à l'esprit que, puisque la colonne SellerID dans
la table Antiques est une clé externe de la table AntiqueOwners, un vendeur
ne sera listé que s'il y a une ligne dans la table AntiqueOwners contenant les
ID et les noms. Nous voulons également éliminer les multiples occurrences du
SellerID dans notre liste, donc, nous utiliserons le mot-clé DISTINCT pour les
colonnes où les répétitions peuvent se produire.
Pour ajouter une difficulté, nous voulons aussi que cette liste soit classée
par ordre alphabétique des Noms, puis des Prénoms (à l'intérieur des noms),
puis des OwnerID (à l'intérieur des noms et des prénoms). Pour cela, nous
utiliserons la clause ORDER BY :
SELECT DISTINCT SELLERID, OWNERLASTNAME, OWNERFIRSTNAME
FROM ANTIQUES, ANTIQUEOWNERS
WHERE SELLERID = OWNERID
ORDER BY OWNERLASTNAME, OWNERFIRSTNAME, OWNERID;
Dans cet exemple, puisque tout le monde a vendu un article, nous aurons une
liste de tous les propriétaires, classés par ordre alphabétique sur les noms.
Pour référence ultérieure (au cas où quelqu'un le demande), ce type de jointure
est considéré comme appartenant à la catégorie des jointures internes.
----------------------------------------------------------------------------
Alias et In/Sous-requêtes
Dans cette section, nous parlerons des Alias, In et de l'utilisation des
sous-requêtes, et de la manière de les utiliser dans un exemple de 3-table.
En premier lieu, regardez cette requête qui imprime le nom des propriétaires
qui ont passé une commande et la nature de cette commande, en ne listant
seulement que les commandes qui peuvent être satisfaites (c'est à dire qu'il
y a un vendeur qui possède l'article commandé) :
SELECT OWN.OWNERLASTNAME Last Name, ORD.ITEMDESIRED Item Ordered
FROM ORDERS ORD, ANTIQUEOWNERS OWN
WHERE ORD.OWNERID = OWN.OWNERID
AND ORD.ITEMDESIRED IN
(SELECT ITEM
FROM ANTIQUES);
Ce qui donne :
Last name Item Ordered
--------- ------------
Smith Table
Smith Desk
Akins Chair
Lawson Mirror
Il y a plusieurs choses à noter à propos de cette requête :
1. Tout d'abord, les mots "Last Name" et "Item Ordered" dans les lignes
SELECT donnent les en-têtes du rapport.
2. Les mots OWN et ORD sont des alias; ce sont de nouveaux noms pour les
deux tables données dans la clause FROM qui sont utilisés comme préfixes
pour toutes les notations point (.) de noms de colonnes dans les requêtes
(voir ci-dessus). Ceci élimine les risques ambiguïté, spécialement dans
l'équi-jointure de la clause WHERE où les deux tables ont une colonne
nommée OwnerID, et cette notation point (.) précise à SQL que nous
désignons deux OwnerID différents de deux tables différentes.
3. Notez que la table des commandes (ORDERS) est indiquée la première dans
la clause FROM; ceci apporte la certitude que la liste sera réalisée à
partir de cette table, et que la table AntiqueOwners
est utilisée uniquement pour obtenir les informations détaillées (Last
Name / Nom).
4. Plus important, la clause AND dans la clause WHERE (OU) force l'utilisation
de la Sous-requête In ("= ANY" ou "= SOME" sont deux utilisations
équivalentes de IN). Cela entraîne que la sous-requête est effectuée,
retournant une liste de tous les articles (Items) appartenant à la table
Antiques, comme s'il n'y avait pas de clause WHERE (OU). Donc, pour lister
une ligne de la table ORDERS, le ItemDesired (article_désiré) doit être
dans la liste retournée des articles appartenant à la table Antiques, et
donc un article ne sera listé que si la commande ne peut être honorée
que par un autre propriétaire. On peut se le représenter comme ceci: la
sous-requête retourne un ensemble d'articles (Items) auquel chaque
ItemDesired (Article_Désiré) dans la table des commandes (ORDERS) est
comparé; la condition IN (DANS) n'est vraie que si le ItemDesired
appartient à l'ensemble provenant de la table ANTIQUES.
5. Notez également, comme c'est le cas ici, qu'il y a un objet ancien pour
chaque demande, ce qui, évidemment, n'est pas toujours le cas... De plus,
notez aussi que, lorsque IN, "= ANY", ou "= SOME" est utilisé, ces
mots-clés font référence à toutes les lignes qui conviennent, pas aux
colonnes... c'est à dire que vous ne pouvez pas mettre de multiples
colonnes dans un clause SELECT de sous-requête, pour tenter de faire
correspondre la colonne de la clause WHERE externe avec l'une des
multiples valeurs de colonnes possibles de la sous-requête; une seule
colonne peut être indiquée dans la sous-requête, et la correspondance
possible provient de multiples valeurs de lignes, dans cette colonne
unique, et non pas l'inverse.
Ouf! Ce sera tout sur ce sujet des requêtes SELECT complexes pour l'instant.
Maintenait, voyons d'autres instructions SQL.
----------------------------------------------------------------------------
Instructions SQL Diverses
Fonctions d'Agrégation
Je parlerai de cinq fonctions d'agrégation importantes: SUM, AVG, MAX, MIN, et
COUNT. On les appelle fonctions d'agrégation parce qu'elles résument les
résultats d'une requête, plutôt que de donner une liste de toutes les lignes.
* SUM () donne la somme, pour une colonne donnée, de toutes les lignes qui
satisfont aux conditions requises, et où la colonne donnée est numérique.
* AVG () donne la moyenne de la colonne donnée.
* MAX () donne la plus grande valeur dans la colonne donnée.
* MIN () donne la plus petite valeur dans la colonne donnée.
* COUNT(*) donne le nombre de lignes qui satisfont aux conditions.
En utilisant les tables du début de ce document, regardons trois exemples :
SELECT SUM(SALARY), AVG(SALARY)
FROM EMPLOYEESTATISTICSTABLE;
Cette requête donne la somme des de salaires tous les salariés présents dans
la table et le salaire moyen.
SELECT MIN(BENEFITS)
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION = 'Manager';
Cette requête donne le chiffre de la colonne indemnités le plus faible des
employés qui sont Managers, cette valeur est 12 500.
SELECT COUNT(*)
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION = 'Staff';
Cette requête vous donne le nombre d'employés ayant le statut de cadre (Staff,
i.e. 3).
----------------------------------------------------------------------------
Les Vues
En SQL, vous pouvez (vérifiez auprès de votre Administrateur de Base de Données,
DBA) avoir accès à la création de vues par vous-même. Une vue vous permet d'affecter
les résultats d'une requête à une nouvelle table personnelle, que vous pourrez
utiliser dans d'autres requêtes, pour laquelle vous donnez le nom de la vue dans
votre clause FROM. Quand vous accédez à une vue, la requête qui est définie dans
l'instruction de création de la vue est effectuée (généralement), et les résultats
de cette requête ont la même allure qu'une autre table dans la requête que vous
avez écrit en invoquant la vue. Par exemple, pour créer une vue :
CREATE VIEW ANTVIEW AS SELECT ITEMDESIRED FROM ORDERS;
Maintenant, écrivons une requête utilisant cette vue comme une table, où la
table est seulement une liste de tous les articles désirés (ITEMDESIRED) de
la table ORDERS :
SELECT SELLERID
FROM ANTIQUES, ANTVIEW
WHERE ITEMDESIRED = ITEM;
Cette table montre tous les Identifiants de Vendeurs (SellerID) de la table
ANTIQUES où l'article (Item) dans cette table apparaît dans la vue ANTVIEW,
qui consiste justement en tous les Articles Désirés (Items Desired) dans la
table ORDERS. La liste est crée en parcourant les articles AntiquesItems un
par un jusqu'à ce qu'il y ait correspondance avec la vue ANTVIEW. Les vues
peuvent être utilisées pour restreindre les accès à la base de données,
ainsi que, dans ce cas, pour simplifier une requête complexe.
----------------------------------------------------------------------------
Création de Nouvelles Tables
Toutes les tables, dans une base de données doivent être créées à un certain
moment... voyons comment mous pourrions créer la table des commandes (ORDERS) :
CREATE TABLE ORDERS
(OWNERID INTEGER NOT NULL,
ITEMDESIRED CHAR(40) NOT NULL);
Cette instruction donne un nom à la table et renseigne le SGBD sur la nature
de chaque colonne de la table. Veuillez noter que cette instruction utilise
des types de données génériques, et que les types de données peuvent être
différents, selon le SGBD que vous utilisez. Comme d'habitude, vérifiez vos
conditions locales. Voici quelques types de données génériques courants:
* Char(x) - Une colonne de caractères, où x est un nombre indiquant le
nombre maximum de caractères permis (taille maximale) de la colonne.
* Integer - Une colonne de nombres entiers, positifs ou négatifs.
* Decimal(x, y) - Une colonne de nombre décimaux, où x est la taille
maximum, en digits, des nombres décimaux dans cette colonne, et y le
nombre maximal de digits autorisés après la virgule. Le nombre maximal
(4,2) sera 99.99.
* Date - Une colonne de date dans un format spécifique au SGBD.
* Logical - Une colonne qui ne peut contenir que deux valeurs: VRAI ou FAUX.
Autre remarque, l'indication NOT NULL (non nul) signifie que la colonne doit
avoir une valeur pour chacune des lignes. Si l'on avait utilisé NULL (nul),
cette colonne peut être laissée vide dans certaines lignes.
----------------------------------------------------------------------------
Modification des tables
Ajoutons une colonne à la table ANTIQUES pour permettre la saisie du prix d'un
article donné :
ALTER TABLE ANTIQUES ADD (PRICE DECIMAL(8,2) NULL);
On verra plus tard comment les données pour cette nouvelle colonne peuvent
être mises à jour ou ajoutées.
----------------------------------------------------------------------------
Ajout de Données
Pour insérer des lignes dans une table, faites ce qui suit :
INSERT INTO ANTIQUES VALUES (21, 01, 'Ottoman', 200.00);
Ceci insère les données dans la table, en tant que nouvelle ligne, colonne
par colonne, dans un ordre prédéfinit. Au lieu de cela, changeons cet ordre
et laissons le Prix vide:
INSERT INTO ANTIQUES (BUYERID, SELLERID, ITEM)
VALUES (01, 21, 'Ottoman');
----------------------------------------------------------------------------
Suppression de données
Supprimons cette nouvelle ligne de la base de données :
DELETE FROM ANTIQUES
WHERE ITEM = 'Ottoman';
Mais s'il y a une autre ligne qui contient 'Ottoman', cette ligne sera
également supprimée. Supprimons toutes les lignes (une, dans ce cas) qui
contient les données spécifiques que nous avons ajouté plus
tôt :
DELETE FROM ANTIQUES
WHERE ITEM = 'Ottoman' AND BUYERID = 01 AND SELLERID = 21;
----------------------------------------------------------------------------
Mise à Jour des Données
Mettons un Prix à jour dans une ligne qui n'en contient pas encore :
UPDATE ANTIQUES SET PRICE = 500.00 WHERE ITEM = 'Chair';
Ceci met le Prix de toutes les Chaises (Chair) à 500.00. Comme indiqué
ci-dessus, conditions WHERE supplémentaires, utilisation de AND, il faut
utiliser ces conditions pour limiter la mise à jour à des lignes spécifiques.
De plus, des colonnes supplémentaires peuvent être renseignées en séparant
les instructions "égal" par des virgules.
----------------------------------------------------------------------------
Considérations Diverses
Index
Les Index permettent à un SGBD d'accéder au données plus rapidement (veuillez
noter que cette fonctionnalité est non-standard/indisponible sur certains
systèmes). Le système crée une structure de donnée interne (l'index) qui
entraîne une sélection de lignes beaucoup plus rapide, quand la sélection
est basée sur des colonnes indexées. Cet index indique au SGBD où se trouve
une certaine ligne dans une table étant donné une valeur de colonne indexée,
exactement comme l'index d'un livre vous indique à quelle page un mot donné
se trouve. Créons un index pour le OwnerID dans la colonne AntiqueOwners :
CREATE INDEX OID_IDX ON ANTIQUEOWNERS (OWNERID);
Maintenant sur les noms:
CREATE INDEX NAME_IDX ON ANTIQUEOWNERS (OWNERLASTNAME, OWNERFIRSTNAME);
Pour être débarrassé d'un index, supprimez le :
DROP INDEX OID_IDX;
A propos, vous pouvez aussi bien "supprimer" une table (attention!--cela
signifie que votre table est détruite). Dans le second exemple, l'index est
construit à partir des deux colonnes, agrégées ensembles--un comportement
bizarre peut résulter de cette situation... vérifiez dans votre manuel avant
d'effectuer une telle opération.
Quelques SGBD n'imposent pas l'utilisation de clés primaires; en d'autres
termes, l'unicité d'une colonne n'est pas imposée automatiquement. Cela
signifie que, par exemple, j'aurais pu essayer d'insérer une autre ligne
dans la table AntiqueOwners avec un OwnerID de 02, quelques systèmes me
permettent de faire cela, bien qu'il ne le faille pas, puisque cette colonne
est supposée être unique dans cette table (chaque valeur de ligne est supposée
être différente). Une manière de contourner cela est de créer un index unique
sur la colonne que nous souhaitons voir être la clé primaire pour forcer le
système à interdire les doubles :
CREATE UNIQUE INDEX OID_IDX ON ANTIQUEOWNERS (OWNERID);
----------------------------------------------------------------------------
GROUP BY et HAVING
Une utilisation spéciale de la clause GROUP BY est l'association d'une fonction
agrégée (spécialement COUNT; qui compte le nombre de lignes dans chaque groupe)
avec des groupes de lignes. Premièrement, supposons que la table ANTIQUES
possède la colonne Prix (Price)t, et que chaque ligne contienne une valeur
dans cette colonne. Nous voulons voir le prix de l'article le plus cher acheté
par chaque propriétaire. Il nous faut donc dire à SQL de grouper les achats de
chacun des propriétaires, et de nous dire le prix d'achat maximum :
SELECT BUYERID, MAX(PRICE)
FROM ANTIQUES
GROUP BY BUYERID;
Maintenant, disons que nous ne voulons voir que le prix maximum si l'achat
dépasse 1000, nous devrons utiliser la clause HAVING :
SELECT BUYERID, MAX(PRICE)
FROM ANTIQUES
GROUP BY BUYERID
HAVING PRICE > 1000;
----------------------------------------------------------------------------
Sous-requêtes Supplémentaires
Un autre usage commun des sous-requêtes amène à l'utilisation des opérateurs
pour permettre à une condition WHERE d'inclure la sortie SELECT d'une
sous-requête. En premier, demandons la liste des acheteurs ayant acheté un
article cher (le prix de cet article est supérieur de 100 au prix moyen de tous
les articles achetés) :
SELECT OWNERID
FROM ANTIQUES
WHERE PRICE >
(SELECT AVG(PRICE) + 100
FROM ANTIQUES);
La sous-requête calcule le Prix moyen, ajoute 100, et, et en utilisant ce
chiffre on imprime un OwnerID pour chaque article coûtant plus que ce chiffre.
On peut utiliser DISTINCT OWNERID, pour éliminer les doubles.
Listons les Noms (Last Names) de ceux qui sont dans la table AntiqueOwners,
SEULEMENT s'ils ont acheté un article :
SELECT OWNERLASTNAME
FROM ANTIQUEOWNERS
WHERE OWNERID =
(SELECT DISTINCT BUYERID
FROM ANTIQUES);
Cette sous-requête retourne une liste des acheteurs, et le Nom du propriétaire
d'un objet ancien est imprimé seulement si l'identificateur du Propriétaire
(Owner's ID) dans la liste obtenue par la sous-requête (appelée quelquefois
liste des candidats).
Voici un exemple de mise à jour: nous savons que la personne qui a acheté la
bibliothèque a un Prénom erroné dans la base de données... Ce devrait être
John :
UPDATE ANTIQUEOWNERS
SET OWNERFIRSTNAME = 'John'
WHERE OWNERID =
(SELECT BUYERID
FROM ANTIQUES
WHERE ITEM = 'Bookcase');
Tout d'abord, la sous-requête trouve le BuyerID pour la (les) personne(s) qui
a (ont) acheté(s) la bibliothèque, puis la requête externe met à jour son
Prénom.
Souvenez vous de cette règle à propos des sous-requêtes: quand vous avez une
sous-requête faisant partie d'une condition WHERE, la clause SELECT dans la
sous-requête doit avoir des colonnes qui correspondent en nombre et en type
à celle de la clause WHERE de la requête externe. En d'autres termes, si vous
avez "WHERE ColumnName = (SELECT...);", le SELECT ne peut faire référence qu'à
une seule colonne, pour pouvoir correspondre à la clause WHERE externe, et
elles doivent être du même type (les deux étant soit entiers, soit chaînes
de caractères, etc.).
----------------------------------------------------------------------------
EXISTS et ALL
EXISTS utilise une sous-requête comme condition, où cette condition est Vraie
si la sous-requête retourne au moins une ligne et Fausse si la sous-requête
n'en retourne aucune; c'est une fonctionnalité qui n'est pas intuitive et
n'est utilisée que dans peu de cas. Cependant, si un client éventuel voulait
consulter la liste des propriétaires pour voir s'il y a des chaises (Chairs),
essayez :
SELECT OWNERFIRSTNAME, OWNERLASTNAME
FROM ANTIQUEOWNERS
WHERE EXISTS
(SELECT *
FROM ANTIQUES
WHERE ITEM = 'Chair');
S'il y a des Chaises (Chair) dans une colonne de la table ANTIQUES, la
sous-requête renverra une ou plusieurs lignes, rendant la clause EXISTS
vraie, ce qui amènera SQL à donner une liste des propriétaires dans
ANTIQUEOWNERS. S'il n'y avait eu aucune Chaise, la requête externe n'aurait
pas renvoyé de ligne.
ALL est une autre fonctionnalité peu commune, et en général, on peut réaliser
une requête avec ALL de manières différentes et éventuellement plus simples;
regardons cet exemple de requête :
SELECT BUYERID, ITEM
FROM ANTIQUES
WHERE PRICE >= ALL
(SELECT PRICE
FROM ANTIQUES);
Ceci va nous retourner l'article de prix le plus élevé (ou plus d'un article
s'il y a des ex-aequo), et son acheteur. La sous-requête renvoie la liste de
tous les Prix (PRICE) dans la table ANTIQUES, puis la requête externe examine
chaque ligne de la table ANTIQUES et si son Prix est supérieur ou égal à chacun
(ou ALL, TOUS) des Prix de cette liste, il est affiché, donnant ainsi l'article
de prix le plus élevé. La raison pour laquelle ">=" doit être utilisé est que
l'article de prix le plus élevé sera égal au prix le plus élevé, puisque cet
Article est dans la liste de Prix.
----------------------------------------------------------------------------
UNION et Jointure Externe
Il y a des occasions où vous pouvez désirer voir ensembles les résultats de
requêtes multiples, leurs sorties étant combinées; pour cela utilisez UNION.
Pour fusionner la sortie des deux requêtes suivantes, en affichant l'identificateur
de tous les Acheteurs plus tous ceux qui ont passé une Commande :
SELECT BUYERID
FROM ANTIQUEOWNERS
UNION
SELECT OWNERID
FROM ORDERS;
Il faut noter que SQL nécessite que les types de données des listes des clauses
SELECT correspondent colonne par colonne. Dans cet exemple, les identificateurs
BuyerID et OwnerID sont du même type (entier). Notez également que SQL
effectue automatiquement une élimination des doubles quand on utilise la clause
UNION (comme si c'étaient deux "ensembles"); dans une requête simple, il faut
utiliser la clause DISTINCT.
La jointure externe est utilisée quand une requête de jointure est "unifiée",
les lignes n'étant pas incluses dans la jointure. Ceci est particulièrement
utile si des "balises" de type constante texte sont inclus. D'abord,
regardez la requête :
SELECT OWNERID, 'is in both Orders & Antiques'
FROM ORDERS, ANTIQUES
WHERE OWNERID = BUYERID
UNION
SELECT BUYERID, 'is in Antiques only'
FROM ANTIQUES
WHERE BUYERID NOT IN
(SELECT OWNERID
FROM ORDERS);
La première requête effectue une jointure pour lister tous les propriétaires
qui sont dans les deux tables, et met une balise après l'identificateur (ID)
en insérant le texte correspondant à la balise. La clause UNION fusionne cette
liste avec la liste suivante. La seconde liste est générée premièrement en
listant les identificateurs (ID) qui ne sont pas dans la table ORDERS, c'est à
dire en générant une liste des ID exclus de la requête de jointure.. Puis,
chaque ligne de la table ANTIQUES est analysée, et, si l'identifiant de
l'acheteur (BuyerID) n'est pas dans cette liste d'exclusion, il est listé avec
le texte correspondant à sa balise. Il y aurait peut-être une meilleure
manière de créer cette liste, mais c'est difficile de générer des balises
informationnelles.
Ce concept est utile dans des situations où une clé primaire est en relation
avec une clé externe, et où la valeur de la clé externe est NULLE (NULL) pour
quelques clés primaires. Par exemple, dans une table, la clé primaire est
vendeur, et dans une autre table client, avec le vendeur enregistré dans la
même ligne. Cependant, si un vendeur n'a pas de clients, le nom de cette
personne n'apparaîtra pas dans la table des clients. Une jointure externe sera
utilisée pour imprimer une liste de tous les vendeurs, avec leurs clients, que
le vendeur ait un client ou pas--c'est à dire qu'il n'y aura pas de client
imprimé (valeur logique NULL) si le vendeur n'a pas de client, mais existe dans
la table des vendeurs. Autrement, le vendeur sera listé avec chaque client.
ASSEZ DE REQUETES!!! Qu'est-ce que vous dites?...Eh bien, maintenant voyons
quelque chose de complètement différent...
----------------------------------------------------------------------------
SQL incorporé--un vilain exemple (n'écrivez pas un programme comme cela... il
est là UNIQUEMENT à titre d'exemple)
/* -Voici un exemple de programme qui utilise le SQL incorporé (Embedded
SQL). Le SQL incorporé permet aux programmeurs de se connecter à une
base de données et d'inclure du code SQL en plein programme, et ainsi,
leurs programmes peuvent utiliser, manipuler, et traiter les données
d'une base de données.
-Cet exemple de Programme C (qui utilise du SQL incorporé) doit imprimer
un rapport.
-Les instructions SQL devront être précompilées avant d'effectuer la
compilation normale.
-Si vous utilisez un langage différent les parties EXEC SQL seront les
mêmes (standard), mais le code C qui les entourent devront être
modifiées, y compris les déclarations de variables hôtes.
-Le SQL incorporé diffère de système à système, aussi, encore une fois,
vérifiez la documentation locale, spécialement les déclarations de
variables et les procédures de connexion pour lesquelles le réseau, le
SGBD, et le système d'exploitation sont cruciaux. */
/***************************************************/
/* CE PROGRAMME N'EST PAS COMPILABLE OU EXECUTABLE */
/* IL EST UNIQUEMENT DONNE A TITRE D'EXEMPLE */
/***************************************************/
#include <stdio.h>
/* Section de déclaration des variables hôtes; ce seront les variables
utilisées par votre programme, mais également celles utilisées par SQL
pour y mettre ou y lire des valeurs,. */
EXEC SQL BEGIN DECLARE SECTION;
int BuyerID;
char Prenom[100], Nom[100], Item[100];
EXEC SQL END DECLARE SECTION;
/* Cette section,insère les variables SQLCA, de façon à pouvoir tester les erreurs. */
EXEC SQL INCLUDE SQLCA;
main() (
/* Ceci est une possibilité pour se connecter à la base de données */
EXEC SQL CONNECT UserID/Password;
/* Cette partie de code soit vous indique que vous êtes connecté soit
teste si un code erreur a été généré, signifiant que la connexion était
incorrecte ou impossible. */
if(sqlca.sqlcode) (
printf(Printer, "Erreur de connexion au serveur de base de données.\n");
exit();
)
printf("Connecté au serveur de base de données.\n");
/* Ici, on déclare un "Curseur". C'est utilisé lorsqu'une requête retourne
plus d'une ligne, et qu'on doit effectuer un traitement sur chaque ligne
obtenue de la requête. Je vais utiliser pour le rapport, chaque ligne obtenue
par cette requête. Ensuite, on utilisera "FETCH" (va chercher) pour récupérer
les lignes, une par une, mais pour que la requête soit effectivement exécutée,
il faut utiliser l'instruction "OPEN". La "Déclaration" (Declare) sert
uniquement à construire la requête. */
EXEC SQL DECLARE ItemCursor CURSOR FOR
SELECT ITEM, BUYERID
FROM ANTIQUES
ORDER BY ITEM;
EXEC SQL OPEN ItemCursor;
/*
+-- Insérer ici un test d'erreur similaire au précédent si vous le désirez --+
*/
/* L'instruction FETCH insère les valeurs de la ligne suivante respectivement
dans chacune des variables hôtes. Cependant un "priming fetch" (technique de
programmation) doit être exécuté en premier. Lorsque le curseur n'a plus de
données un code (sqlcode) est généré nous permettant de sortir de la boucle.
Notez que, pour des raisons de simplicité, on abandonne la boucle pour n'importe
quel sqlcode, même s'il correspond à un code erreur. Autrement, il faut
effectuer un test d'erreur spécifique. */
EXEC SQL FETCH ItemCursor INTO :Item, :BuyerID;
while(!sqlca.sqlcode) (
/* Nous effectuerons également deux traitements pour chaque ligne. Premièrement,
augmenter le prix de 5 (rétribution du marchand) et ensuite, lire le nom de
l'acheteur pour le mettre dans le rapport. Pour faire cela, j'utiliserai les
instructions Update et Select, avant d'imprimer la ligne sur l'écran. La mise à
jour suppose, cependant, qu'un acheteur donné n'a acheté qu'un seul article,
ou, sinon, le prix sera augmenté de trop nombreuses fois. Sinon, il aurait
fallu utiliser une logique "RowID" (consulter la documentation). De plus,
notez la présence du signe : (deux points) qui doit être placé devant les
noms de variables hôtes quand elles sont utilisées dans des instructions
SQL. */
EXEC SQL UPDATE ANTIQUES
SET PRICE = PRICE + 5
WHERE ITEM = :Item AND BUYERID = :BuyerID;
EXEC SQL SELECT OWNERFIRSTNAME, OWNERLASTNAME
INTO :Prenom, :Nom
FROM ANTIQUEOWNERS
WHERE BUYERID = :BuyerID;
printf("%25s %25s %25s", Prenom, Nom, Item);
/* Rapport grossier--uniquement à but d'exemple! Aller chercher la ligne suivante */
EXEC SQL FETCH ItemCursor INTO :Item, :BuyerID;
)
/* Fermer le curseur, enregistrer les modifications (voir ci-dessous),
et quitter le programme. */
EXEC SQL CLOSE DataCursor;
EXEC SQL COMMIT RELEASE;
exit();
)
----------------------------------------------------------------------------
Questions courantes sur SQL--Sujets avancés
(Consulter les liens FAQ pour en avoir plusieurs autres)
1. Pourquoi ne puis-je pas demander uniquement les trois premières lignes
d'une table? --Parce que, dans une base de données relationnelle, les
lignes sont insérées sans aucun ordre particulier, c'est à dire que le
système les insèrent dans un ordre arbitraire; de ce fait, vous ne pouvez
demander des lignes qu'en utilisant des fonctionnalités SQL valides,
telles que ORDER BY, etc.
2. Que sont ces DDL et DML dont j'entends parler ? --DDL (Data
Definition Language - Langage de Définition de Données) fait référence à
(en SQL) l'instruction de Création de Table (Create Table)...DML (Data
Manipulation Language - Langage de Manipulation de Données) fait référence
aux instructions Select, Update, Insert, et Delete.
3. Les tables des base de données ne sont elles pas simplement des fichiers?
--Eh bien, les SGBD stockent les données dans des fichiers déclarés par
le gestionnaire du système avant que de nouvelles tables ne soient créées
(sur les grands systèmes), mais le système stocke les données dans un
format spécial, et peut répartir les données d'une table dans plusieurs
fichiers. Dans le monde des bases de données, un ensemble de fichiers
créés pour une base de données est appelé un "espace de tables". En
général, sur les petits systèmes, tout ce qui concerne une base de données
(définitions et toutes les tables de données) est stocké dans un seul
fichier.
4. (Question en relation avec la précédente) Les bases de données ne sont
elles pas simplement que des tableurs? --Non, et ceci pour deux raisons.
Premièrement, les tableurs peuvent avoir des données dans une cellule, mais
une cellule est plus qu'une intersection ligne-colonne. Selon votre
tableur, une cellule peut aussi contenir des formules et un formatage,
ce que les bases de données (actuelles) ne permettent pas. Deuxièmement,
les cellules dépendent souvent des données présentes dans d'autres
cellules. Dans les bases de données, les "cellules" sont indépendantes,
sauf que les colonnes sont en relation logique (heureusement: ensembles,
une ligne et une colonne décrivent une entité), et, en dehors des
contraintes de clé primaire et de clé externe, chaque ligne d'une table
est indépendante des autres.
5. Comment puis-je importer un fichier texte de données dans une base de
données? --Eh bien, vous ne pouvez pas le faire directement...il vous faut
utiliser un programme utilitaire, tel que le SQL*Loader pour Oracle,
ou écrire un programme pour charger les données dans la base de données.
Un programme pour réaliser cela lit simplement chaque enregistrement du
fichier texte, le sépare en colonnes, et effectue une insertion (INSERT)
dans la base de données.
6. Qu'est-ce qu'un schéma? --Un schéma est un ensemble logique de tables, tel
que la base de données ANTIQUES ci-dessus...habituellement, on s'y réfère
simplement en tant que "base de données", mais une base de données peut
contenir plus d'un schéma. Par exemple, un schéma en étoile est un ensemble
de tables où une table centrale, de grande taille, contient toutes les
informations importantes, et est liée, via des clés externes, à des tables
de dimension qui contiennent l'information détaillée, et qui peuvent être
utilisées dans une jointure pour créer des rapports détaillés.
7. Quels conseils généraux pourriez vous donner pour rendre mes requêtes SQL
et mes bases de données meilleures et plus rapides (optimisées)?
o Vous devriez essayer, si vous le pouvez, d'éviter, dans les clauses
SELECT, des expressions telles que SELECT ColumnA + ColumnB, etc.
L'optimiseur de requêtes de la base de données, partie du SGBD qui
détermine la meilleure manière d'extraire les données requises de la
base de données elle-même, traite les expressions d'une façon telle
que cela demande en général plus de temps pour extraire les données
que si les colonnes avaient été sélectionnées normalement, et que
l'expression elle-même calculée par programme.
o Minimisez le nombre de colonnes incluses dans une clause Group By.
o Si vous effectuez une jointure, tâchez d'avoir les colonnes, de cette
jointure, indexées (dans les deux tables).
o Si vous avez un doute, créez un index.
o A moins que vous ne fassiez de multiple comptages ou une requête
complexe, utilisez COUNT(*) (le nombre de lignes sera généré par la
requête) plutôt que COUNT(Column_Name).
8. Qu'est-ce que la Normalisation? --La Normalisation est une technique de
conception de base de données qui suggère qu'un certain critère doit être
pris en compte quand on définit l'organisation des tables (prise de
décision sur le nombre de colonnes de chaque table, et création de la
structure des clés), où l'idée est d'éliminer la redondance à travers les
tables des données qui ne sont pas des clés. On parle de la normalisation
en s'y référant habituellement en termes de "formes", et j'introduirais ici
uniquement les trois premières, bien qu'il soit tout à fait courant d'en
utiliser d'autres formes, plus avancées (quatrième, cinquième, Boyce-Codd;
consultez la documentation).
La Première Forme Normale consiste à placer les données dans des tables
séparées où les données dans chaque tables sont de type similaire, et à
donner à chaque table une clé primaire.
Mettre les données en Seconde Forme Normale consiste à mettre les données
dans les tables où elle ne dépendent uniquement que d'une partie de la clé.
Par exemple, si j'avais laissé les noms des propriétaires d'objets anciens
dans la table des articles, ce n'aurait pas été une seconde forme normale
puisque les données auraient été redondantes; le nom aurait dû être
répété pour chaque article possédé, donc, les noms ont été placés dans
leur propre table. Les noms en eux-mêmes n'ont rien à voir avec les
articles, seules les identités des acheteurs et des vendeurs sont
concernées.
La Troisième Forme Normale consiste à se débarrasser, dans une table, à
tout ce qui ne dépend pas uniquement de la clé primaire. On met uniquement
l'information qui dépend de la clé, et l'on déplace, dans d'autres tables,
tout ce qui est indépendant de la clé primaire, et l'on crée des clés
primaires pour les nouvelles tables.
Il y a une certaine forme de redondance dans chaque forme, et si les
données sont en 3NF (abrégé pour 3ième forme normale), elles sont déjà en
1NF et 2NF. En terme d'organisation des données, organisez vos données de
façon que les colonnes qui ne sont pas des clés primaires dépendent
seulement de la clé primaire entière. Si vous jetez un oeil sur la base de
données en exemple, vous verrez que, lorsque vous naviguez à travers la
base de données, c'est au travers de jointures qui utilisent les colonnes
de clé commune.
Deux autre points importants dans la conception de bases de données sont
l'utilisation de noms significatifs, bien choisis, cohérents et logiques
pour les tables et les colonnes et l'utilisation de noms significatifs pour
la base de données elle-même. Sur le dernier point, ma base de données
pèche, puisque j'utilise des codes numériques comme identificateurs. C'est
en général bien meilleur d'utiliser, si possible, des clés qui ont, en
elles-mêmes, un sens; par exemple, une meilleure clé pourrait consister
des quatre premières lettres du nom et de la première initiale du prénom,
comme JONEB pour Bill Jones (ou pour éviter les doubles, ajoutez-y des
nombres à la fin pour différencier deux ou plusieurs personnes ayant le
même nom, ainsi, on pourrait essayer JONEB1, JONEB2, etc.).
9. Quelle est la différence entre une requête simple ligne et une requête
multi-lignes et pourquoi est-ce important de connaître cette
différence? --Premièrement, pour parler de ce qui est évident, une requête
simple ligne est une requête qui retourne une ligne unique comme résultat,
et le résultat d'une requête multi-lignes est constitué de plusieurs
lignes. Qu'une requête retourne une ligne ou plusieurs dépend complètement
de la conception (ou schéma) des tables qui constituent la base de données.
Assurez-vous d'inclure suffisamment de conditions, et structurez vos
instructions SQL correctement, de façon à obtenir le résultat désiré (soit
une ligne, soit plusieurs). Par exemple, si vous vouliez être sûr qu'une
requête sur la table AntiqueOwners ne retourne qu'une ligne, employez une
condition d'égalité sur la clé primaire, OwnerID.
Trois raisons, concernant l'importance de ce sujet, viennent immédiatement
à l'esprit.
Premièrement, l'obtention de plusieurs lignes alors que vous n'en attendez
qu'une, ou vice-versa, peut signifier que la requête est erronée, que la
base de données est incomplète, ou simplement que vous découvrez quelque
chose de nouveau concernant vos données.
Deuxièmement, si vous utilisez une instruction de mise à jour (UPDATE) ou
de suppression (DELETE), il vaudrait mieux vous assurer que l'instruction
que vous écrivez effectue bien l'opération sur la ligne désirée (ou les
lignes)...ou sinon, vous pourriez supprimer ou mettre à jour plus de lignes
que vous ne le désirez.
Troisièmement, il faut soigneusement penser au nombre de lignes qui seront
retournées pour toutes les requêtes rédigées en SQL incorporé. Si vous
écrivez une requête simple ligne, une seule instruction SQL peut suffire
pour satisfaire à la logique du programme. D'un autre côté, si votre
requête retourne de multiples lignes, il vous faudra utiliser
l'instruction FETCH, et très certainement quelque chose comme une structure
de boucle sera nécessaire dans votre programme pour traiter chaque ligne
retournée par la requête.
10. Que sont les relations? --C'est une autre question de conception...le
terme "relation" fait habituellement référence aux relations entre clés
primaires et externes entre les tables. Ce concept est important parce que,
quand les tables d'une base de données relationnelle sont conçues, ces
relations doivent être définies parce que cela détermine quelles colonnes
sont ou ne sont pas des clés primaires ou externes. Vous avez peut-être
entendu parler des diagrammes Entités-Relations, qui sont une
représentation graphique des tables dans les schéma de la base de données.
Voyez l'exemple de diagramme à la fin de cette section ou consultez
quelques sites indiqués ci-dessous concernant ce sujet, car il y a de
nombreuses manières de dessiner les diagrammes E-R. Mais d'abord, jetons
un oeil à chaque type de relation...
Une relation 1-à-1 (ou 1:1, ou 1-1) signifie que vous avez une colonne clé
primaire et que chaque clé primaire est en relation avec une clé externe.
Par exemple, dans le premier exemple, dans la table des adresses des
employés TableAdresseEmploye nous avons une colonne numéro d'identification
de l'employé (EmployeeIDNo). Donc, la table TableAdresseEmploye est en
relation avec la table EmployeeStatisticsTable (deuxième exemple de table)
par l'intermédiaire du numéro EmployeeIDNo. Plus précisément, chaque
employé, de la table TableAdresseEmploye possède des statistiques (une
ligne de données) dans la table EmployeeStatisticsTable. Même si c'est un
exemple inventé, c'est une relation "1-1". Inscrivez en caractères gras le
"has" ("a" ou "possède")...quand on décrit une relation, il est important
de décrire une relation en utilisant un verbe.
Les deux autres types de relations peuvent ou pas utiliser une clé primaire
logique et des contraintes par rapport aux clés externes...cela dépend
strictement des souhaits du concepteur. La première de ces relations est la
relation un-à-plusieurs ("1-M").
Cela signifie que pour chaque valeur d'une colonne dans une table, il y a
une ou plusieurs valeurs correspondantes dans une autre table. Des
contraintes de clé peuvent être ajoutées au modèle, ou éventuellement une
colonne d'identification peut être utilisée pour établir une relation. Un
exemple serait que pour chaque OwnerID dans la table AntiqueOwners, il y
ait un ou plusieurs (la valeur zéro est également autorisée) articles
(Items) achetés dans la table ANTIQUES (verbe: acheter).
Finalement, la relation plusieurs-à plusieurs ("M-M") n'utilise
généralement pas de clés, et habituellement utilise des identificateurs de
colonnes. L'apparition inhabituelle d'une relation "M-M" signifie qu'une
colonne, dans une table est en relation avec une autre colonne dans une
autre table, et que pour chaque valeur de l'une de ces deux colonnes, il y
a une ou plusieurs valeurs correspondantes dans la colonne correspondante
de l'autre table (et vice-versa), ou possibilité plus courante, les deux
tables ont une relation 1-M avec l'autre (deux relations, une 1-M dans
chaque direction). Un [mauvais] exemple de la situation la plus courante
consisterait, si vous avez une bases de données de fonctions, à avoir une
table possédant une ligne pour chaque employé et sa fonction, et d'avoir
une autre table contenant une ligne pour chaque fonction avec un des
employés l'occupant. Dans ce cas, vous auriez plusieurs lignes pour chaque
employé dans la première table, une pour chaque fonction, et plusieurs
lignes pour chaque fonction dans le seconde table, une pour chaque employé
ayant cette fonction.
Ces tables sont en relation M-M: chaque employé, dans la première table a
plusieurs fonctions dans la seconde table, et chaque fonction, dans la
seconde table, a plusieurs attributaires dans la première table. Ceci est
la partie émergée de l'iceberg concernant ce sujet...consultez les liens
ci-dessous pour avoir de plus amples informations et regardez le diagramme
ci-dessous donnant un exemple simplifié de diagramme E-R.
[Exemple Simplifié de Diagramme Entités-Relations]
11. Quelles sont quelques unes des fonctionnalités importantes, non standard,
de SQL (Question extrêmement courante)? --Eh bien, nous allons voir çà dans
la section suivante...
----------------------------------------------------------------------------
SQL Non-standard..."A vérifier pour votre site"
* INTERSECT et MINUS sont comme des instructions UNION , sauf que INTERSECT
produits des lignes qui apparaissent dans les deux requêtes, et que MINUS
produit des lignes provenant de la première requête mais pas de la
seconde.
* Fonctionnalités de la Génération de Rapport: la clause COMPUTE est placée
à la fin d'une requête pour placer le résultat d'une fonction agrégée à
la fin d'une liste, comme COMPUTE SUM (PRICE); Une autre solution est
d'utiliser une logique d'interruption: définir une interruption pour
diviser les résultats de la requête en groupes basés sur une colonne,
comme BREAK ON BUYERID. Alors, pour sortir un résultat après la liste d'un
groupe, utilisez COMPUTE SUM OF PRICE ON BUYERID. Si, par exemple, vous
avez utilisé ces trois clauses ("BREAK" en premier, "COMPUTE on break" en
second, "COMPUTE overall sum" en troisième), vous obtiendrez un rapport qui
regroupera les articles par acheteurs, listera la somme de Prix pour chaque
groupe d'articles d'un acheteur, puis, après que tous les groupes aient été
listés, listera la somme de tous les Prix, le tout, avec des en-têtes et
des lignes générés par SQL.
* En plus des fonctions agrégées indiquées ci-dessus, quelques SGBD ont des
fonctions supplémentaires qui peuvent être utilisées dans des listes de
sélection (SELECT), sauf que ces fonctions (quelques fonctions caractères
autorisent des résultats de plusieurs lignes) doivent être utilisées avec
une valeur individuelle (pas de groupes), pour des requêtes simple ligne.
De plus, les fonctions ne doivent être utilisées qu' avec les types de
données appropriés. Voici quelques Fonctions Mathématiques:
ABS(X) Valeur A-convertit les nombres négatifs en nombres positifs
et laisse les positifs inchangés
CEIL(X) X est une valeur décimale qui sera arrondie à la valeur
supérieure.
FLOOR(X) X est une valeur décimale qui sera arrondie à la valeur
inférieure.
GREATEST(X,Y)Retourne la plus grande des deux valeurs.
LEAST(X,Y) Retourne la plus petite des deux valeur.
MOD(X,Y) Retourne le reste de X / Y.
POWER(X,Y) Retourne X à la puissance Y.
ROUND(X,Y) Arrondit X à Y positions décimales. i Y n'est pas donné, X
est arrondi à la valeur de l'entier le plus proche.
SIGN(X) Retourne le signe - si X < 0, sinon retourne un signe plus.
SQRT(X) Retourne la racine carrée de X.
Fonctions Caractères
LEFT(<string>,X)
Retourne les X caractères les plus à gauche de la
chaîne de caractères.
RIGHT(<string>,X)
Retourne les X caractères les plus à droite de la
chaîne de caractères.
UPPER(<string>)
Convertit tous les caractères de la chaîne en
majuscules.
LOWER(<string>)
Convertit tous les caractères de la chaîne en
minuscules.
INITCAP(<string>)
Convertit les caractères initiaux de la chaîne en
Capitales.
LENGTH(<string>)
Retourne le nombre de caractères de la chaîne.
<string>||<string>
Combine les deux chaînes en une seule chaîne,
concaténée, où la première chaîne est immédiatement
suivie par la seconde.
LPAD(<string>,X,'*')
Insère des caractères * (ou n'importe quel autre, mis
entre guillemets) à gauche de la chaîne de
caractères pour lui donner une longueur de X
caractères.
RPAD(<string>,X,'*')
Insère des caractères * (ou n'importe quel autre, mis
entre guillemets) à droite de la chaîne de
caractères pour lui donner une longueur de X
caractères.
SUBSTR(<string>,X,Y)
Extrait Y lettres de la chaîne à partir de la
position X.
NVL(<column>,<value>)
La fonction NVL va substituer la valeur <value>
pour chaque valeur nulle dans la colonne <column>. Si
la valeur courante dans la colonne <column> n'est pas
nulle (NULL), NVL est sans effet.
----------------------------------------------------------------------------
Résumé de la Syntaxe--Pour Utilisateurs Avancés Seulement
Voici la forme générale des instructions dont il a été question dans ce
didacticiel, avec, en plus, quelques autres, (des explications sont données).
SOUVENEZ-VOUS que toutes ces instructions peuvent ne pas être disponibles sur
votre système, aussi vérifiez leur disponibilité dans la documentation:
ALTER TABLE <TABLE NAME> ADD|DROP|MODIFY (COLUMN SPECIFICATION[S]...voir
Create Table); --vous permet d'ajouter ou de supprimer une ou plusieurs colonnes
d'une table, ou de changer les spécifications(données, types, etc.) d'une colonne
existante;
cette instruction est également utilisée pour changer les spécifications
physiques d'une table
(comment la table est stockée, etc.), mais ces définitions sont spécifiques au
SGBD, aussi, lire la documentation. De même, ces spécifications physiques sont
utilisées avec les instructions de création de table, lorsqu'une table est créée
pour la première fois. De plus, seulement une seule option peut être exécutée
par instruction de modification: (Alter Table)--soit add (ajout), drop
(suppression), OU modify (modification) dans une simple instruction.
COMMIT; --rend les modifications effectuées sur une bases de données permanentes
(depuis le dernier COMMIT; connu sous le nom de transaction)
CREATE [UNIQUE] INDEX <INDEX NAME>
ON <TABLE NAME> (<COLUMN LIST>); --UNIQUE est optionnel; entre parenthèses.
CREATE TABLE <TABLE NAME>
(<COLUMN NAME> <DATA TYPE> [(<SIZE>)] <COLUMN CONSTRAINT>,
...autres colonnes); (valide également avec ALTER TABLE)
--où SIZE est uniquement utilisé avec certains types de données (voir
ci-dessus), et les contraintes incluent les possibilités suivantes (imposé
automatiquement par le SGBD;
(un non respect entraîne la génération d'une erreur) :
1. NULL ou NOT NULL (voir ci-dessus)
2. UNIQUE impose que deux lignes ne peuvent avoir la même valeur pour cette
colonne
3. PRIMARY KEY indique à la base de données que cette colonne est la colonne
clé primaire (utilisé uniquement si la clé est une colonne clé, autrement une
instruction
PRIMARY KEY (column, column, ...) apparaît après la dernière définition de
colonne.
4. CHECK permet de tester une condition quand on insère ou on met à jour une
donnée dans cette colonne; par exemple, CHECK (PRICE > 0) amène le système à
tester si la colonne Prix est supérieure ou égale à zéro avant d'accepter la
valeur...quelquefois implanté comme instruction CONSTRAINT.
5. DEFAULT insère une valeur par défaut dans la base de données si l'on veut
insérer une ligne qui ne contienne pas de valeur pour cette colonne; par
exemple,
BENEFITS INTEGER DEFAULT = 10000
6. FOREIGN KEY fonctionne comme la Clé Primaire, mais est suivi par:
REFERENCES <TABLE NAME> (<COLUMN NAME>), qui fait référence à la clé primaire
de référence.
CREATE VIEW <TABLE NAME> AS <QUERY>;
DELETE FROM <TABLE NAME> WHERE <CONDITION>;
INSERT INTO <TABLE NAME> [(<COLUMN LIST>)]
VALUES (<VALUE LIST>);
ROLLBACK; --Annule toutes les modifications effectuées dans la base de données,
celles qui ont été faites depuis la dernière commande COMMIT...Attention!
Quelques logiciels travaillant en transactions, donc, la commande ROLLBACK peut
ne pas fonctionner.
SELECT [DISTINCT|ALL] <LIST OF COLUMNS, FUNCTIONS, CONSTANTS, ETC.>
FROM <LIST OF TABLES OR VIEWS>
[WHERE <CONDITION(S)>]
[GROUP BY <GROUPING COLUMN(S)>]
[HAVING <CONDITION>]
[ORDER BY <ORDERING COLUMN(S)> [ASC|DESC]]; --où ASC|DESC permet le classement en
ordre ascendant (ASCending) ou descendant (DESCending)
UPDATE <TABLE NAME>
SET <COLUMN NAME> = <VALUE>
[WHERE <CONDITION>]; --si la clause WHERE n'est pas donnée, toutes les lignes
seront mises à jour selon l'instruction SET
----------------------------------------------------------------------------
Liens Importants
Liens Informatique & SQL/DB : Netscape -- Oracle -- Sybase -- Informix
--Microsoft
Page de Référence -- Ask the SQL Pro -- SQL Pro's Relational DB
Sites Utiles
Programmer's Source -- DBMS Sites -- inquiry.com -- DB Ingredients
Web Authoring -- Computing Dictionary -- DBMS Lab/Links -- SQL FAQ -- SQL
Databases
RIT Database Design Page -- Database Jump Site -- Didacticiels de programmation sur le Web
Ressources pour le Développement -- Query List -- IMAGE SQL
Divers: CNN -- USA Today -- Pathfinder -- ZDNet -- Metroscope -- CNet
Liste de ressources sur Internet -- Netcast Weather -- TechWeb -- LookSmart
Moteurs de Recherche: Yahoo -- Alta Vista -- Excite -- WebCrawler -- Lycos --
Infoseek -- search.com
L'auteur n'est pas reponsable de ces sites.
----------------------------------------------------------------------------
Avertissement
J'espère que vous aurez appris quelque chose de ce premier regard sur un langage
très important qui est en train de devenir plus répandu dans le mode de
l'informatique client-serveur. J'ai rédigé cette page web pour apporter quelque
chose d'utile au web et à la communauté des utilisateurs du web. En réalité,
j'ai appris que ce document est utilisé dans plusieurs collèges pour des cours
sur les bases de données et par des chercheurs. En outre, lisez cette page dans
le nouveau livre, édité par Waite Publishing, sur Borland C++ Builder, qui sera
publié cet été et dans une version à venir chez Sams Publishing. De plus, je
voudrais remercier tous les gens, sur les cinq continents, qui m'ont contactés
à propos de cette page.
J'espère aussi continuer à ajouter plus d'éléments à ce didacticiel, tels que
des articles sur la conception d'une base de données et les extensions SQL non
standard, même si je souhaite me tenir à l'écart de particularités propres à
un Système de Gestion de Base de Donnée. Bonne chance pour vos développements
en SQL et autres aventures informatiques.
Jim Hoffman
----------------------------------------------------------------------------
Commentaires ou Suggestions? Envoyez-moi un courrier électronique à jhoffman@one.net.
Ou vous pouvez désirer jeter un oeil aux pages Web de Jim Hoffman's Web Pages
pour plus d'informations me concernant.
Copyright 1996-1997, James Hoffman. Ce document peut être utilisé gratuitement
par n'importe quel utilisateur d'Internet, mais ne peut pas être inclus dans
un autre document, publié sous une autre forme, ou produit en masse de quelque
façon que ce soit.
Netscape Navigator donne le meilleur affichage de cette page; celui-ci n'est pas
très bon si l'on utilise Microsoft Internet Explorer.
Dernière mise à jour : 8-25-1997; ajout de quelques éléments.