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.html Référence SQL
http://www.inquiry.com/techtips/thesqlpro/ Demandez le Pro. de SQL
http://www.inquiry.com/techtips/thesqlpro/usefulsites.html Sites utiles au Pro. du SGBD Relationnel SQL
http://infoweb.magi.com/~steve/develop.html Les 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.html Ingrédients pour SGBD
http://www.stars.com/Tutorial/CGI/ Création Web
http://wfn-shop.princeton.edu/cgi-bin/foldoc Dictionnaire d'Informatique
http://www-ccs.cs.umass.edu/db.html DBMS 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.html SGBD SQL
http://www.it.rit.edu/~wjs/IT/199602/icsa720/icsa720postings.html Page de Conception de Bases de Données RIT
http://www.pcslink.com/~ej/dbweb.html Site de liens vers des Bases de Données http://www.eng.uc.edu/~jtilley/tutorial.html Didacticiels de programmation sur le Web
http://www.ndev.com/ndc2/support/resources.htp Ressources pour le Développement
http://ashok.pair.com/sql.htm Liste de Requêtes
http://jazz.external.hp.com/training/sqltables/main.html IMAGE SQL Diverses
http://www.eit.com/web/netservices.html Liste de Ressources Internet
Voici, ci-dessous, un extrait de la page d'accueil du didacticiel SQL.
Introduction au Langage de Requete Structure
Version 3.31
Cette page contient un didacticiel du Langage de Requete Structure( Structured
Query Language, egalement connu sous le nom de SQL). Ce didacticiel constitue
une nouveaute sur le World Wide Web, car c'est le premier didacticiel SQL
complet disponible sur l'Internet. SQL permet l'acces aux donnees dans les
systemes de gestion de bases de donnees relationnels tels que Oracle,
Sybase, Informix, Microsoft SQL Server, Access, et autres en permettant aux
utilisateurs de decrire les donnees qu'ils desirent obtenir. SQL permet aussi
aux utilisateurs de definir l'organisation des donnees dans la base et de les
manipuler. Le but de cette page est de decrire l'utilisation de SQL, et de
donner des exemples. C'est le langage ANSI SQL, ou standard SQL, qui sera
utilise dans ce document. Il ne sera pas question ici des fonctionnalites
specifiques a un SGBD particulier, qui seront traitees dans la section "SQL
non-standard". Nous vous recommandons d'imprimer cette page afin de pouvoir
vous referer facilement aux differents exemples.
----------------------------------------------------------------------------
Table des matieres
Principes fondamentaux de l'instruction SELECT
Selection Conditionnelle
Operateurs Relationnels
Conditions Composees
IN & BETWEEN
Utilisation de LIKE
Jointures
Cles
Realisation d'une Jointure
Elimination des Doubles
Alias & In/Sous-requetes
Fonctions d'Agregation
Vues
Creation de Nouvelles Tables
Modification des Tables
Ajout de Donnees
Suppression de Donnees
Mise a Jour des Donnees
Index
GROUP BY & HAVING
Sous-requetes Supplementaires
EXISTS & ALL
UNION & Jointures Externes
SQL Integre
Questions Courantes sur SQL
SQL Non-standard
Resume de la Syntaxe
Liens Importants
----------------------------------------------------------------------------
Principes fondamentaux de l'instruction SELECT
Dans une base de donnees relationnelle, les donnees sont stockees dans des
tables. Par exemple, une table pourrait mettre en relation le Numero de
Securite 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 employe.
On utilisera SELECT, comme ceci :
SELECT Prenom, Nom, Adresse, Ville, Etat
FROM TableAdresseEmploye;
Voici le resultat de l'interrogation de notre base de donnees :
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 donnees de la table TableAdresseEmploye les colonnes nommees Prenom, Nom,
Adresse, Ville et Etat. Noter que les noms de colonnes et les noms de tables
sont sans espaces... ils doivent etre saisis en un seul mot; et que
l'instruction se termine par un point-virgule (;). La forme generale 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 a taper tous les noms
de colonne, utiliser :
SELECT * FROM NomTable;
Chaque Systeme de Gestion de Base de Donnees (SGBD) et chaque logiciel de
base de donnees utilisent differentes methodes pour se connecter a la base
de donnee et pour entrer les instructions SQL; consultez le "guru" de votre
ordinateur pour qu'il vous aide a vous connecter de facon a pouvoir utiliser
SQL.
----------------------------------------------------------------------------
Selection Conditionnelle
Pour etudier plus avant l'instruction SELECT , jetons un oeil a un nouvel exemple de table
(exemple uniquement hypothetique) :
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
----------------------------------------------------------------------------
Operateurs Relationnels
Il y a six Operateurs Relationnels en SQL, et, apres les avoir presentes,
nous verrons comment les utiliser :
= Egal
<> or !=
(voir le manuel) Different
< Plus Petit Que
> Plus Grand Que
<= Plus Petit Que ou Egal a
>= Plus Grand Que ou Egal a
La clause WHERE est utilisee pour specifier que l'on affichera seulement
certaines ligne de la table, selon un critere definit par cette clause WHERE.
Ce sera plus clair en prenant une paire d'exemples.
Si l'on desire voir les numeros d'identification des employes (EMPLOYEEIDNO)
dont le salaire est egal ou superieur a 50 000, on utilisera la requete
suivante :
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE SALARY >= 50000;
Noter que le symbole >= (plus grand que ou egal a) est utilise, puisque l'on
desire voir tout ceux qui gagnent plus de 50 000, ou 50 000, sur la meme
liste. On aura l'affichage :
EMPLOYEEIDNO
------------
010
105
152
215
244
La description de WHERE, SALARY >= 50000, est appelee une condition. On pourrait
effectuer le meme traitement sur des colonnes de texte :
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION = 'Manager';
Ceci entrainera l'affichage des Numeros d'Identification de tous les Managers.
En general, avec les colonnes contenant du texte, n'utiliser que egal a ou
different de, et assurez vous que tout texte apparaissant dans l'instruction
est entoure d'apostrophes (').
----------------------------------------------------------------------------
Conditions plus complexes: Conditions Composees
L'operateur AND (ET) combine deux ou plusieurs conditions et n'affiche une
ligne que si cette ligne satisfait TOUTES les conditions requises (i.e. ou
toutes les conditions sont realisees). Par exemple, pour afficher tout le
personnel gagnant plus 40 000, ecrire :
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE SALARY > 40000 AND POSITION = 'Staff';
L'operateur 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 recoivent moins de 10
000 en participation aux benefices, utilisez la requete suivante :
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE SALARY < 40000 OR BENEFITS < 10000;
Les operateurs AND et OR peuvent etre combines, 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 superieure a 60 000 et celle de position est egale a
Manager, puis, a partir de cette liste de lignes, SQL recherche alors celles
qui satisfont a la condition AND (ET) precedente ou a la condition specifiant
que la colonne Indemnites est superieure a 12 000. En consequence, SQL n'affiche
seulement que cette seconde liste de lignes, en gardant a l'esprit que tous ceux
dont les Indemnites sont superieures a 12 000 en feront partie puisque l'operateur
OR (OU) inclue la ligne si l'une des conditions est verifiee. Notez en passant
que l'operation AND (ET) est effectuee en premier.
Pour generaliser ce processus, SQL effectue l(es) operation(s) AND pour determiner
les lignes ou l(es) operation(s) AND sont verifiees (souvenez-vous bien : toutes
les conditions sont verifiees), puis ces resultats sont utilises pour tester les
conditions OR, et, ne seront affichees que les lignes ou les conditions requises
par l'operateur OR seront verifiees.
Pour que les OR's soient effectues avant les AND's, par exemple si vous vouliez voir
une liste des employes dont le salaire est eleve (>50 000) OU beneficiant d'indemnites
importantes (>10 000), ET qui soient cadres, utilisez des parentheses :
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION = 'Manager' AND (SALARY > 50000 OR BENEFIT > 10000);
----------------------------------------------------------------------------
IN et BETWEEN
Une methode plus facile pour utiliser les conditions composees consiste a utiliser
IN ou BETWEEN. Par exemple, si vous desirez 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 superieur ou egal a 30 000, mais inferieur
ou egal a 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 criteres, essayez :
SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE SALARY NOT BETWEEN 30000 AND 50000;
De la meme facon, NOT IN donne la liste de toutes les lignes exclues de la liste
obtenue par l'operateur 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 utilise pour representer n'importe quel caractere
possible (nombre, lettre, ou signe de ponctuation) ou ensemble de caracteres
qui peut apparaitre apres le "L". Pour trouver les gens dont le Nom se termine
avec "L", utiliser '%L', ou si vous desirez le "L" au milieu du mot, essayez
'%L%'. Le symbole '%' peut etre utilise pour n'importe quel caractere, et
dont la position est relative par rapport a des caracteres donnes. NOT LIKE
affiche les lignes qui ne correspondent pas a la description donnee. Il y a
d'autres manieres d'utiliser LIKE, de meme que n'importe lesquelles des
conditions composees dont nous venons de parler, bien que cela depende du SGBD
que vous utilisez; comme d'habitude, consultez un manuel ou le gestionnaire ou
administrateur de votre systeme pour en connaitre les fonctionnalites, ou
simplement, assurez vous que ce que vous essayer de faire est possible et
autorise. Cet avertissement est aussi valable pour les fonctionnalites de SQL
exposees ci-dessous. Cette section est donnee a titre d'exemple des requetes
qui peuvent etre ecrites en SQL.
----------------------------------------------------------------------------
Jointures
Dans cette section, nous allons parler uniquement des jointures internes et
des equi-jointures, dans la mesure ou ce sont les plus utiles. Pour avoir plus
d'informations, voyez les liens sur des sites SQL au bas de cette page.
On suggere qu'une bonne maniere de concevoir une base de donnees implique que
chaque table ne contienne des donnees qui ne concernent qu'une seule entite,
et que des informations detaillees peuvent etre obtenues, dans une base de
donnees relationnelle, en utilisant des tables supplementaires et en effectuant
une jointure.
Premierement, jetons un oeil a 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
----------------------------------------------------------------------------
Cles
En premier lieu, nous allons parler du concept de cles. Une cle primaire est
une colonne ou en ensemble de colonnes qui identifie de maniere unique les
autres donnees d'une ligne donnee. Par exemple, dans la table AntiqueOwners,
la colonne OwnerID identifie de maniere unique cette ligne. Ceci signifie deux
choses: que deux lignes ne peuvent avoir le meme OwnerID, et que, meme si
deux proprietaires les memes noms et prenoms la colonne OwnerID garantit que
ces deux proprietaires ne seront pas confondus l'un avec l'autre, puisque la
colonne OwnerID unique sera utilisee a travers la base de donnees pour se
referer a un proprietaire, plutot que son nom.
Une cle externe est une colonne d'une table qui est cle primaire d'une autre
table, ce qui signifie que toutes les donnees d'une cle externe doivent avoir
des donnees correspondantes dans l'autre table, ou cette colonne est la cle
primaire.
Pour parler SGBD, cette correspondance est connue sous le nom d'integre
referentielle. Par exemple, dans la table Antiques, BuyerID et SellerID sont
tous les deux des cles externes a la cle primaire de la table AntiqueOwners
(OwnerID; pour les besoins de notre argumentation, on doit d'abord etre
reference dans la table AntiqueOwners avant de pouvoir acheter ou vendre quoi
que ce soit), puisque, dans les deux tables, les colonnes ID sont utilisees
pour identifier les proprietaires, les acheteurs ou les vendeurs, et que
OwnerID est la cle primaire de la table AntiqueOwners. En d'autres termes,
toutes ces donnees "ID" sont utilisees pour se referer aux proprietaires,
acheteurs et vendeurs sans avoir a utiliser les noms effectifs.
----------------------------------------------------------------------------
Realisation d'une jointure
Le but de ces cles est ainsi de pouvoir mettre en relation les donnees a
travers les tables sans avoir a repeter les donnees dans chaque tables,
--c'est toute la puissance des bases de donnees relationnelles. Par exemple,
on peut trouver les noms de ceux qui ont achete une chaise sans avoir a lister
la totalite du nom de l'acheteur dans la table Antiques... vous pouvez trouver
ce nom en mettant en relation ceux qui ont achete une chaise avec les noms
dans la table AntiqueOwners en utilisant le OwnerID, qui met en relation les
donnees dans les deux tables. Pour trouver les noms de ceux qui ont achete
une chaise, utilisez la requete suivante :
SELECT OWNERLASTNAME, OWNERFIRSTNAME
FROM ANTIQUEOWNERS, ANTIQUES
WHERE BUYERID = OWNERID AND ITEM = 'Chair';
Notez ce qui suit au sujet de cette requete... notez que les deux tables mise
en jeux dans cette relation sont listees 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 a ceux qui ont achete (et, dans cet exemple, de ce
fait possedent) une chaise. En second lieu, notez comment les colonnes ID sont
mises en relation d'une table a la suivante par l'utilisation de la clause
BUYERID = OWNERID. Ne seront listes que les noms de la table AntiqueOwners
dont les ID correspondent a travers les tables et dont l'article achete est
une chaise (a cause du AND). Parce que la condition de jointure utilisee est
un signe egal, cette jointure est appelee une equi-jointures. le resultat de
cette requete donnera deux noms: Smith, Bob et Fowler, Sam.
La notation avec un point (.) fait reference a l'utilisation du nom de colonne
en suffixe du nom de table pour eviter toute ambiguite, 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 differents dans chaque table,
cela n'etait pas necessaire.
----------------------------------------------------------------------------
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 antiquite. Evidemment, vous ne desirez
une liste ou chaque vendeur n'apparait qu'une fois--vous ne voulez pas savoir
combien d'antiquites ont ete vendues par une personne, mais uniquement le fait
que cette personne en a vendu une (pour les comptages, voir la fonction
d'Agregation ci-dessous). Cela signifie qu'il vous faudra dire a SQL d'eliminer
les doubles des lignes des ventes, et de ne seulement lister chaque personne
qu'une fois. Pour realiser cela, utilisez le mot-cle DISTINCT.
Premierement, vous aurez besoin de faire un equi-jointures sur la table
AntiqueOwners pour obtenir les donnees concernant le Nom et le Prenom de la
personne. Cependant, gardez a l'esprit que, puisque la colonne SellerID dans
la table Antiques est une cle externe de la table AntiqueOwners, un vendeur
ne sera liste que s'il y a une ligne dans la table AntiqueOwners contenant les
ID et les noms. Nous voulons egalement eliminer les multiples occurrences du
SellerID dans notre liste, donc, nous utiliserons le mot-cle DISTINCT pour les
colonnes ou les repetitions peuvent se produire.
Pour ajouter une difficulte, nous voulons aussi que cette liste soit classee
par ordre alphabetique des Noms, puis des Prenoms (a l'interieur des noms),
puis des OwnerID (a l'interieur des noms et des prenoms). 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 proprietaires, classes par ordre alphabetique sur les noms.
Pour reference ulterieure (au cas ou quelqu'un le demande), ce type de jointure
est considere comme appartenant a la categorie des jointures internes.
----------------------------------------------------------------------------
Alias et In/Sous-requetes
Dans cette section, nous parlerons des Alias, In et de l'utilisation des
sous-requetes, et de la maniere de les utiliser dans un exemple de 3-table.
En premier lieu, regardez cette requete qui imprime le nom des proprietaires
qui ont passe une commande et la nature de cette commande, en ne listant
seulement que les commandes qui peuvent etre satisfaites (c'est a dire qu'il
y a un vendeur qui possede l'article commande) :
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 a noter a propos de cette requete :
1. Tout d'abord, les mots "Last Name" et "Item Ordered" dans les lignes
SELECT donnent les en-tetes du rapport.
2. Les mots OWN et ORD sont des alias; ce sont de nouveaux noms pour les
deux tables donnees dans la clause FROM qui sont utilises comme prefixes
pour toutes les notations point (.) de noms de colonnes dans les requetes
(voir ci-dessus). Ceci elimine les risques ambiguite, specialement dans
l'equi-jointure de la clause WHERE ou les deux tables ont une colonne
nommee OwnerID, et cette notation point (.) precise a SQL que nous
designons deux OwnerID differents de deux tables differentes.
3. Notez que la table des commandes (ORDERS) est indiquee la premiere dans
la clause FROM; ceci apporte la certitude que la liste sera realisee a
partir de cette table, et que la table AntiqueOwners
est utilisee uniquement pour obtenir les informations detaillees (Last
Name / Nom).
4. Plus important, la clause AND dans la clause WHERE (OU) force l'utilisation
de la Sous-requete In ("= ANY" ou "= SOME" sont deux utilisations
equivalentes de IN). Cela entraine que la sous-requete est effectuee,
retournant une liste de tous les articles (Items) appartenant a 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_desire) doit etre
dans la liste retournee des articles appartenant a la table Antiques, et
donc un article ne sera liste que si la commande ne peut etre honoree
que par un autre proprietaire. On peut se le representer comme ceci: la
sous-requete retourne un ensemble d'articles (Items) auquel chaque
ItemDesired (Article_Desire) dans la table des commandes (ORDERS) est
compare; la condition IN (DANS) n'est vraie que si le ItemDesired
appartient a l'ensemble provenant de la table ANTIQUES.
5. Notez egalement, comme c'est le cas ici, qu'il y a un objet ancien pour
chaque demande, ce qui, evidemment, n'est pas toujours le cas... De plus,
notez aussi que, lorsque IN, "= ANY", ou "= SOME" est utilise, ces
mots-cles font reference a toutes les lignes qui conviennent, pas aux
colonnes... c'est a dire que vous ne pouvez pas mettre de multiples
colonnes dans un clause SELECT de sous-requete, pour tenter de faire
correspondre la colonne de la clause WHERE externe avec l'une des
multiples valeurs de colonnes possibles de la sous-requete; une seule
colonne peut etre indiquee dans la sous-requete, 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 requetes SELECT complexes pour l'instant.
Maintenait, voyons d'autres instructions SQL.
----------------------------------------------------------------------------
Instructions SQL Diverses
Fonctions d'Agregation
Je parlerai de cinq fonctions d'agregation importantes: SUM, AVG, MAX, MIN, et
COUNT. On les appelle fonctions d'agregation parce qu'elles resument les
resultats d'une requete, plutot que de donner une liste de toutes les lignes.
* SUM () donne la somme, pour une colonne donnee, de toutes les lignes qui
satisfont aux conditions requises, et ou la colonne donnee est numerique.
* AVG () donne la moyenne de la colonne donnee.
* MAX () donne la plus grande valeur dans la colonne donnee.
* MIN () donne la plus petite valeur dans la colonne donnee.
* COUNT(*) donne le nombre de lignes qui satisfont aux conditions.
En utilisant les tables du debut de ce document, regardons trois exemples :
SELECT SUM(SALARY), AVG(SALARY)
FROM EMPLOYEESTATISTICSTABLE;
Cette requete donne la somme des de salaires tous les salaries presents dans
la table et le salaire moyen.
SELECT MIN(BENEFITS)
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION = 'Manager';
Cette requete donne le chiffre de la colonne indemnites le plus faible des
employes qui sont Managers, cette valeur est 12 500.
SELECT COUNT(*)
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION = 'Staff';
Cette requete vous donne le nombre d'employes ayant le statut de cadre (Staff,
i.e. 3).
----------------------------------------------------------------------------
Les Vues
En SQL, vous pouvez (verifiez aupres de votre Administrateur de Base de Donnees,
DBA) avoir acces a la creation de vues par vous-meme. Une vue vous permet d'affecter
les resultats d'une requete a une nouvelle table personnelle, que vous pourrez
utiliser dans d'autres requetes, pour laquelle vous donnez le nom de la vue dans
votre clause FROM. Quand vous accedez a une vue, la requete qui est definie dans
l'instruction de creation de la vue est effectuee (generalement), et les resultats
de cette requete ont la meme allure qu'une autre table dans la requete que vous
avez ecrit en invoquant la vue. Par exemple, pour creer une vue :
CREATE VIEW ANTVIEW AS SELECT ITEMDESIRED FROM ORDERS;
Maintenant, ecrivons une requete utilisant cette vue comme une table, ou la
table est seulement une liste de tous les articles desires (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 ou l'article (Item) dans cette table apparait dans la vue ANTVIEW,
qui consiste justement en tous les Articles Desires (Items Desired) dans la
table ORDERS. La liste est cree en parcourant les articles AntiquesItems un
par un jusqu'a ce qu'il y ait correspondance avec la vue ANTVIEW. Les vues
peuvent etre utilisees pour restreindre les acces a la base de donnees,
ainsi que, dans ce cas, pour simplifier une requete complexe.
----------------------------------------------------------------------------
Creation de Nouvelles Tables
Toutes les tables, dans une base de donnees doivent etre creees a un certain
moment... voyons comment mous pourrions creer la table des commandes (ORDERS) :
CREATE TABLE ORDERS
(OWNERID INTEGER NOT NULL,
ITEMDESIRED CHAR(40) NOT NULL);
Cette instruction donne un nom a la table et renseigne le SGBD sur la nature
de chaque colonne de la table. Veuillez noter que cette instruction utilise
des types de donnees generiques, et que les types de donnees peuvent etre
differents, selon le SGBD que vous utilisez. Comme d'habitude, verifiez vos
conditions locales. Voici quelques types de donnees generiques courants:
* Char(x) - Une colonne de caracteres, ou x est un nombre indiquant le
nombre maximum de caracteres permis (taille maximale) de la colonne.
* Integer - Une colonne de nombres entiers, positifs ou negatifs.
* Decimal(x, y) - Une colonne de nombre decimaux, ou x est la taille
maximum, en digits, des nombres decimaux dans cette colonne, et y le
nombre maximal de digits autorises apres la virgule. Le nombre maximal
(4,2) sera 99.99.
* Date - Une colonne de date dans un format specifique 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 utilise NULL (nul),
cette colonne peut etre laissee vide dans certaines lignes.
----------------------------------------------------------------------------
Modification des tables
Ajoutons une colonne a la table ANTIQUES pour permettre la saisie du prix d'un
article donne :
ALTER TABLE ANTIQUES ADD (PRICE DECIMAL(8,2) NULL);
On verra plus tard comment les donnees pour cette nouvelle colonne peuvent
etre mises a jour ou ajoutees.
----------------------------------------------------------------------------
Ajout de Donnees
Pour inserer des lignes dans une table, faites ce qui suit :
INSERT INTO ANTIQUES VALUES (21, 01, 'Ottoman', 200.00);
Ceci insere les donnees dans la table, en tant que nouvelle ligne, colonne
par colonne, dans un ordre predefinit. Au lieu de cela, changeons cet ordre
et laissons le Prix vide:
INSERT INTO ANTIQUES (BUYERID, SELLERID, ITEM)
VALUES (01, 21, 'Ottoman');
----------------------------------------------------------------------------
Suppression de donnees
Supprimons cette nouvelle ligne de la base de donnees :
DELETE FROM ANTIQUES
WHERE ITEM = 'Ottoman';
Mais s'il y a une autre ligne qui contient 'Ottoman', cette ligne sera
egalement supprimee. Supprimons toutes les lignes (une, dans ce cas) qui
contient les donnees specifiques que nous avons ajoute plus
tot :
DELETE FROM ANTIQUES
WHERE ITEM = 'Ottoman' AND BUYERID = 01 AND SELLERID = 21;
----------------------------------------------------------------------------
Mise a Jour des Donnees
Mettons un Prix a 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) a 500.00. Comme indique
ci-dessus, conditions WHERE supplementaires, utilisation de AND, il faut
utiliser ces conditions pour limiter la mise a jour a des lignes specifiques.
De plus, des colonnes supplementaires peuvent etre renseignees en separant
les instructions "egal" par des virgules.
----------------------------------------------------------------------------
Considerations Diverses
Index
Les Index permettent a un SGBD d'acceder au donnees plus rapidement (veuillez
noter que cette fonctionnalite est non-standard/indisponible sur certains
systemes). Le systeme cree une structure de donnee interne (l'index) qui
entraine une selection de lignes beaucoup plus rapide, quand la selection
est basee sur des colonnes indexees. Cet index indique au SGBD ou se trouve
une certaine ligne dans une table etant donne une valeur de colonne indexee,
exactement comme l'index d'un livre vous indique a quelle page un mot donne
se trouve. Creons 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 etre debarrasse 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 detruite). Dans le second exemple, l'index est
construit a partir des deux colonnes, agregees ensembles--un comportement
bizarre peut resulter de cette situation... verifiez dans votre manuel avant
d'effectuer une telle operation.
Quelques SGBD n'imposent pas l'utilisation de cles primaires; en d'autres
termes, l'unicite d'une colonne n'est pas imposee automatiquement. Cela
signifie que, par exemple, j'aurais pu essayer d'inserer une autre ligne
dans la table AntiqueOwners avec un OwnerID de 02, quelques systemes me
permettent de faire cela, bien qu'il ne le faille pas, puisque cette colonne
est supposee etre unique dans cette table (chaque valeur de ligne est supposee
etre differente). Une maniere de contourner cela est de creer un index unique
sur la colonne que nous souhaitons voir etre la cle primaire pour forcer le
systeme a interdire les doubles :
CREATE UNIQUE INDEX OID_IDX ON ANTIQUEOWNERS (OWNERID);
----------------------------------------------------------------------------
GROUP BY et HAVING
Une utilisation speciale de la clause GROUP BY est l'association d'une fonction
agregee (specialement COUNT; qui compte le nombre de lignes dans chaque groupe)
avec des groupes de lignes. Premierement, supposons que la table ANTIQUES
possede 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 achete
par chaque proprietaire. Il nous faut donc dire a SQL de grouper les achats de
chacun des proprietaires, 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
depasse 1000, nous devrons utiliser la clause HAVING :
SELECT BUYERID, MAX(PRICE)
FROM ANTIQUES
GROUP BY BUYERID
HAVING PRICE > 1000;
----------------------------------------------------------------------------
Sous-requetes Supplementaires
Un autre usage commun des sous-requetes amene a l'utilisation des operateurs
pour permettre a une condition WHERE d'inclure la sortie SELECT d'une
sous-requete. En premier, demandons la liste des acheteurs ayant achete un
article cher (le prix de cet article est superieur de 100 au prix moyen de tous
les articles achetes) :
SELECT OWNERID
FROM ANTIQUES
WHERE PRICE >
(SELECT AVG(PRICE) + 100
FROM ANTIQUES);
La sous-requete calcule le Prix moyen, ajoute 100, et, et en utilisant ce
chiffre on imprime un OwnerID pour chaque article coutant plus que ce chiffre.
On peut utiliser DISTINCT OWNERID, pour eliminer les doubles.
Listons les Noms (Last Names) de ceux qui sont dans la table AntiqueOwners,
SEULEMENT s'ils ont achete un article :
SELECT OWNERLASTNAME
FROM ANTIQUEOWNERS
WHERE OWNERID =
(SELECT DISTINCT BUYERID
FROM ANTIQUES);
Cette sous-requete retourne une liste des acheteurs, et le Nom du proprietaire
d'un objet ancien est imprime seulement si l'identificateur du Proprietaire
(Owner's ID) dans la liste obtenue par la sous-requete (appelee quelquefois
liste des candidats).
Voici un exemple de mise a jour: nous savons que la personne qui a achete la
bibliotheque a un Prenom errone dans la base de donnees... Ce devrait etre
John :
UPDATE ANTIQUEOWNERS
SET OWNERFIRSTNAME = 'John'
WHERE OWNERID =
(SELECT BUYERID
FROM ANTIQUES
WHERE ITEM = 'Bookcase');
Tout d'abord, la sous-requete trouve le BuyerID pour la (les) personne(s) qui
a (ont) achete(s) la bibliotheque, puis la requete externe met a jour son
Prenom.
Souvenez vous de cette regle a propos des sous-requetes: quand vous avez une
sous-requete faisant partie d'une condition WHERE, la clause SELECT dans la
sous-requete doit avoir des colonnes qui correspondent en nombre et en type
a celle de la clause WHERE de la requete externe. En d'autres termes, si vous
avez "WHERE ColumnName = (SELECT...);", le SELECT ne peut faire reference qu'a
une seule colonne, pour pouvoir correspondre a la clause WHERE externe, et
elles doivent etre du meme type (les deux etant soit entiers, soit chaines
de caracteres, etc.).
----------------------------------------------------------------------------
EXISTS et ALL
EXISTS utilise une sous-requete comme condition, ou cette condition est Vraie
si la sous-requete retourne au moins une ligne et Fausse si la sous-requete
n'en retourne aucune; c'est une fonctionnalite qui n'est pas intuitive et
n'est utilisee que dans peu de cas. Cependant, si un client eventuel voulait
consulter la liste des proprietaires 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-requete renverra une ou plusieurs lignes, rendant la clause EXISTS
vraie, ce qui amenera SQL a donner une liste des proprietaires dans
ANTIQUEOWNERS. S'il n'y avait eu aucune Chaise, la requete externe n'aurait
pas renvoye de ligne.
ALL est une autre fonctionnalite peu commune, et en general, on peut realiser
une requete avec ALL de manieres differentes et eventuellement plus simples;
regardons cet exemple de requete :
SELECT BUYERID, ITEM
FROM ANTIQUES
WHERE PRICE >= ALL
(SELECT PRICE
FROM ANTIQUES);
Ceci va nous retourner l'article de prix le plus eleve (ou plus d'un article
s'il y a des ex-aequo), et son acheteur. La sous-requete renvoie la liste de
tous les Prix (PRICE) dans la table ANTIQUES, puis la requete externe examine
chaque ligne de la table ANTIQUES et si son Prix est superieur ou egal a chacun
(ou ALL, TOUS) des Prix de cette liste, il est affiche, donnant ainsi l'article
de prix le plus eleve. La raison pour laquelle ">=" doit etre utilise est que
l'article de prix le plus eleve sera egal au prix le plus eleve, puisque cet
Article est dans la liste de Prix.
----------------------------------------------------------------------------
UNION et Jointure Externe
Il y a des occasions ou vous pouvez desirer voir ensembles les resultats de
requetes multiples, leurs sorties etant combinees; pour cela utilisez UNION.
Pour fusionner la sortie des deux requetes suivantes, en affichant l'identificateur
de tous les Acheteurs plus tous ceux qui ont passe une Commande :
SELECT BUYERID
FROM ANTIQUEOWNERS
UNION
SELECT OWNERID
FROM ORDERS;
Il faut noter que SQL necessite que les types de donnees des listes des clauses
SELECT correspondent colonne par colonne. Dans cet exemple, les identificateurs
BuyerID et OwnerID sont du meme type (entier). Notez egalement que SQL
effectue automatiquement une elimination des doubles quand on utilise la clause
UNION (comme si c'etaient deux "ensembles"); dans une requete simple, il faut
utiliser la clause DISTINCT.
La jointure externe est utilisee quand une requete de jointure est "unifiee",
les lignes n'etant pas incluses dans la jointure. Ceci est particulierement
utile si des "balises" de type constante texte sont inclus. D'abord,
regardez la requete :
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 premiere requete effectue une jointure pour lister tous les proprietaires
qui sont dans les deux tables, et met une balise apres l'identificateur (ID)
en inserant le texte correspondant a la balise. La clause UNION fusionne cette
liste avec la liste suivante. La seconde liste est generee premierement en
listant les identificateurs (ID) qui ne sont pas dans la table ORDERS, c'est a
dire en generant une liste des ID exclus de la requete de jointure.. Puis,
chaque ligne de la table ANTIQUES est analysee, et, si l'identifiant de
l'acheteur (BuyerID) n'est pas dans cette liste d'exclusion, il est liste avec
le texte correspondant a sa balise. Il y aurait peut-etre une meilleure
maniere de creer cette liste, mais c'est difficile de generer des balises
informationnelles.
Ce concept est utile dans des situations ou une cle primaire est en relation
avec une cle externe, et ou la valeur de la cle externe est NULLE (NULL) pour
quelques cles primaires. Par exemple, dans une table, la cle primaire est
vendeur, et dans une autre table client, avec le vendeur enregistre dans la
meme ligne. Cependant, si un vendeur n'a pas de clients, le nom de cette
personne n'apparaitra pas dans la table des clients. Une jointure externe sera
utilisee pour imprimer une liste de tous les vendeurs, avec leurs clients, que
le vendeur ait un client ou pas--c'est a dire qu'il n'y aura pas de client
imprime (valeur logique NULL) si le vendeur n'a pas de client, mais existe dans
la table des vendeurs. Autrement, le vendeur sera liste avec chaque client.
ASSEZ DE REQUETES!!! Qu'est-ce que vous dites?...Eh bien, maintenant voyons
quelque chose de completement different...
----------------------------------------------------------------------------
SQL incorpore--un vilain exemple (n'ecrivez pas un programme comme cela... il
est la UNIQUEMENT a titre d'exemple)
/* -Voici un exemple de programme qui utilise le SQL incorpore (Embedded
SQL). Le SQL incorpore permet aux programmeurs de se connecter a une
base de donnees et d'inclure du code SQL en plein programme, et ainsi,
leurs programmes peuvent utiliser, manipuler, et traiter les donnees
d'une base de donnees.
-Cet exemple de Programme C (qui utilise du SQL incorpore) doit imprimer
un rapport.
-Les instructions SQL devront etre precompilees avant d'effectuer la
compilation normale.
-Si vous utilisez un langage different les parties EXEC SQL seront les
memes (standard), mais le code C qui les entourent devront etre
modifiees, y compris les declarations de variables hotes.
-Le SQL incorpore differe de systeme a systeme, aussi, encore une fois,
verifiez la documentation locale, specialement les declarations de
variables et les procedures de connexion pour lesquelles le reseau, le
SGBD, et le systeme 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 declaration des variables hotes; ce seront les variables
utilisees par votre programme, mais egalement celles utilisees 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,insere les variables SQLCA, de facon a pouvoir tester les erreurs. */
EXEC SQL INCLUDE SQLCA;
main() (
/* Ceci est une possibilite pour se connecter a la base de donnees */
EXEC SQL CONNECT UserID/Password;
/* Cette partie de code soit vous indique que vous etes connecte soit
teste si un code erreur a ete genere, signifiant que la connexion etait
incorrecte ou impossible. */
if(sqlca.sqlcode) (
printf(Printer, "Erreur de connexion au serveur de base de donnees.\n");
exit();
)
printf("Connecte au serveur de base de donnees.\n");
/* Ici, on declare un "Curseur". C'est utilise lorsqu'une requete retourne
plus d'une ligne, et qu'on doit effectuer un traitement sur chaque ligne
obtenue de la requete. Je vais utiliser pour le rapport, chaque ligne obtenue
par cette requete. Ensuite, on utilisera "FETCH" (va chercher) pour recuperer
les lignes, une par une, mais pour que la requete soit effectivement executee,
il faut utiliser l'instruction "OPEN". La "Declaration" (Declare) sert
uniquement a construire la requete. */
EXEC SQL DECLARE ItemCursor CURSOR FOR
SELECT ITEM, BUYERID
FROM ANTIQUES
ORDER BY ITEM;
EXEC SQL OPEN ItemCursor;
/*
+-- Inserer ici un test d'erreur similaire au precedent si vous le desirez --+
*/
/* L'instruction FETCH insere les valeurs de la ligne suivante respectivement
dans chacune des variables hotes. Cependant un "priming fetch" (technique de
programmation) doit etre execute en premier. Lorsque le curseur n'a plus de
donnees un code (sqlcode) est genere nous permettant de sortir de la boucle.
Notez que, pour des raisons de simplicite, on abandonne la boucle pour n'importe
quel sqlcode, meme s'il correspond a un code erreur. Autrement, il faut
effectuer un test d'erreur specifique. */
EXEC SQL FETCH ItemCursor INTO :Item, :BuyerID;
while(!sqlca.sqlcode) (
/* Nous effectuerons egalement deux traitements pour chaque ligne. Premierement,
augmenter le prix de 5 (retribution 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'ecran. La mise a
jour suppose, cependant, qu'un acheteur donne n'a achete qu'un seul article,
ou, sinon, le prix sera augmente de trop nombreuses fois. Sinon, il aurait
fallu utiliser une logique "RowID" (consulter la documentation). De plus,
notez la presence du signe : (deux points) qui doit etre place devant les
noms de variables hotes quand elles sont utilisees 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 a 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 avances
(Consulter les liens FAQ pour en avoir plusieurs autres)
1. Pourquoi ne puis-je pas demander uniquement les trois premieres lignes
d'une table? --Parce que, dans une base de donnees relationnelle, les
lignes sont inserees sans aucun ordre particulier, c'est a dire que le
systeme les inserent dans un ordre arbitraire; de ce fait, vous ne pouvez
demander des lignes qu'en utilisant des fonctionnalites SQL valides,
telles que ORDER BY, etc.
2. Que sont ces DDL et DML dont j'entends parler ? --DDL (Data
Definition Language - Langage de Definition de Donnees) fait reference a
(en SQL) l'instruction de Creation de Table (Create Table)...DML (Data
Manipulation Language - Langage de Manipulation de Donnees) fait reference
aux instructions Select, Update, Insert, et Delete.
3. Les tables des base de donnees ne sont elles pas simplement des fichiers?
--Eh bien, les SGBD stockent les donnees dans des fichiers declares par
le gestionnaire du systeme avant que de nouvelles tables ne soient creees
(sur les grands systemes), mais le systeme stocke les donnees dans un
format special, et peut repartir les donnees d'une table dans plusieurs
fichiers. Dans le monde des bases de donnees, un ensemble de fichiers
crees pour une base de donnees est appele un "espace de tables". En
general, sur les petits systemes, tout ce qui concerne une base de donnees
(definitions et toutes les tables de donnees) est stocke dans un seul
fichier.
4. (Question en relation avec la precedente) Les bases de donnees ne sont
elles pas simplement que des tableurs? --Non, et ceci pour deux raisons.
Premierement, les tableurs peuvent avoir des donnees 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 donnees (actuelles) ne permettent pas. Deuxiemement,
les cellules dependent souvent des donnees presentes dans d'autres
cellules. Dans les bases de donnees, les "cellules" sont independantes,
sauf que les colonnes sont en relation logique (heureusement: ensembles,
une ligne et une colonne decrivent une entite), et, en dehors des
contraintes de cle primaire et de cle externe, chaque ligne d'une table
est independante des autres.
5. Comment puis-je importer un fichier texte de donnees dans une base de
donnees? --Eh bien, vous ne pouvez pas le faire directement...il vous faut
utiliser un programme utilitaire, tel que le SQL*Loader pour Oracle,
ou ecrire un programme pour charger les donnees dans la base de donnees.
Un programme pour realiser cela lit simplement chaque enregistrement du
fichier texte, le separe en colonnes, et effectue une insertion (INSERT)
dans la base de donnees.
6. Qu'est-ce qu'un schema? --Un schema est un ensemble logique de tables, tel
que la base de donnees ANTIQUES ci-dessus...habituellement, on s'y refere
simplement en tant que "base de donnees", mais une base de donnees peut
contenir plus d'un schema. Par exemple, un schema en etoile est un ensemble
de tables ou une table centrale, de grande taille, contient toutes les
informations importantes, et est liee, via des cles externes, a des tables
de dimension qui contiennent l'information detaillee, et qui peuvent etre
utilisees dans une jointure pour creer des rapports detailles.
7. Quels conseils generaux pourriez vous donner pour rendre mes requetes SQL
et mes bases de donnees meilleures et plus rapides (optimisees)?
o Vous devriez essayer, si vous le pouvez, d'eviter, dans les clauses
SELECT, des expressions telles que SELECT ColumnA + ColumnB, etc.
L'optimiseur de requetes de la base de donnees, partie du SGBD qui
determine la meilleure maniere d'extraire les donnees requises de la
base de donnees elle-meme, traite les expressions d'une facon telle
que cela demande en general plus de temps pour extraire les donnees
que si les colonnes avaient ete selectionnees normalement, et que
l'expression elle-meme calculee par programme.
o Minimisez le nombre de colonnes incluses dans une clause Group By.
o Si vous effectuez une jointure, tachez d'avoir les colonnes, de cette
jointure, indexees (dans les deux tables).
o Si vous avez un doute, creez un index.
o A moins que vous ne fassiez de multiple comptages ou une requete
complexe, utilisez COUNT(*) (le nombre de lignes sera genere par la
requete) plutot que COUNT(Column_Name).
8. Qu'est-ce que la Normalisation? --La Normalisation est une technique de
conception de base de donnees qui suggere qu'un certain critere doit etre
pris en compte quand on definit l'organisation des tables (prise de
decision sur le nombre de colonnes de chaque table, et creation de la
structure des cles), ou l'idee est d'eliminer la redondance a travers les
tables des donnees qui ne sont pas des cles. On parle de la normalisation
en s'y referant habituellement en termes de "formes", et j'introduirais ici
uniquement les trois premieres, bien qu'il soit tout a fait courant d'en
utiliser d'autres formes, plus avancees (quatrieme, cinquieme, Boyce-Codd;
consultez la documentation).
La Premiere Forme Normale consiste a placer les donnees dans des tables
separees ou les donnees dans chaque tables sont de type similaire, et a
donner a chaque table une cle primaire.
Mettre les donnees en Seconde Forme Normale consiste a mettre les donnees
dans les tables ou elle ne dependent uniquement que d'une partie de la cle.
Par exemple, si j'avais laisse les noms des proprietaires d'objets anciens
dans la table des articles, ce n'aurait pas ete une seconde forme normale
puisque les donnees auraient ete redondantes; le nom aurait du etre
repete pour chaque article possede, donc, les noms ont ete places dans
leur propre table. Les noms en eux-memes n'ont rien a voir avec les
articles, seules les identites des acheteurs et des vendeurs sont
concernees.
La Troisieme Forme Normale consiste a se debarrasser, dans une table, a
tout ce qui ne depend pas uniquement de la cle primaire. On met uniquement
l'information qui depend de la cle, et l'on deplace, dans d'autres tables,
tout ce qui est independant de la cle primaire, et l'on cree des cles
primaires pour les nouvelles tables.
Il y a une certaine forme de redondance dans chaque forme, et si les
donnees sont en 3NF (abrege pour 3ieme forme normale), elles sont deja en
1NF et 2NF. En terme d'organisation des donnees, organisez vos donnees de
facon que les colonnes qui ne sont pas des cles primaires dependent
seulement de la cle primaire entiere. Si vous jetez un oeil sur la base de
donnees en exemple, vous verrez que, lorsque vous naviguez a travers la
base de donnees, c'est au travers de jointures qui utilisent les colonnes
de cle commune.
Deux autre points importants dans la conception de bases de donnees sont
l'utilisation de noms significatifs, bien choisis, coherents et logiques
pour les tables et les colonnes et l'utilisation de noms significatifs pour
la base de donnees elle-meme. Sur le dernier point, ma base de donnees
peche, puisque j'utilise des codes numeriques comme identificateurs. C'est
en general bien meilleur d'utiliser, si possible, des cles qui ont, en
elles-memes, un sens; par exemple, une meilleure cle pourrait consister
des quatre premieres lettres du nom et de la premiere initiale du prenom,
comme JONEB pour Bill Jones (ou pour eviter les doubles, ajoutez-y des
nombres a la fin pour differencier deux ou plusieurs personnes ayant le
meme nom, ainsi, on pourrait essayer JONEB1, JONEB2, etc.).
9. Quelle est la difference entre une requete simple ligne et une requete
multi-lignes et pourquoi est-ce important de connaitre cette
difference? --Premierement, pour parler de ce qui est evident, une requete
simple ligne est une requete qui retourne une ligne unique comme resultat,
et le resultat d'une requete multi-lignes est constitue de plusieurs
lignes. Qu'une requete retourne une ligne ou plusieurs depend completement
de la conception (ou schema) des tables qui constituent la base de donnees.
Assurez-vous d'inclure suffisamment de conditions, et structurez vos
instructions SQL correctement, de facon a obtenir le resultat desire (soit
une ligne, soit plusieurs). Par exemple, si vous vouliez etre sur qu'une
requete sur la table AntiqueOwners ne retourne qu'une ligne, employez une
condition d'egalite sur la cle primaire, OwnerID.
Trois raisons, concernant l'importance de ce sujet, viennent immediatement
a l'esprit.
Premierement, l'obtention de plusieurs lignes alors que vous n'en attendez
qu'une, ou vice-versa, peut signifier que la requete est erronee, que la
base de donnees est incomplete, ou simplement que vous decouvrez quelque
chose de nouveau concernant vos donnees.
Deuxiemement, si vous utilisez une instruction de mise a jour (UPDATE) ou
de suppression (DELETE), il vaudrait mieux vous assurer que l'instruction
que vous ecrivez effectue bien l'operation sur la ligne desiree (ou les
lignes)...ou sinon, vous pourriez supprimer ou mettre a jour plus de lignes
que vous ne le desirez.
Troisiemement, il faut soigneusement penser au nombre de lignes qui seront
retournees pour toutes les requetes redigees en SQL incorpore. Si vous
ecrivez une requete simple ligne, une seule instruction SQL peut suffire
pour satisfaire a la logique du programme. D'un autre cote, si votre
requete retourne de multiples lignes, il vous faudra utiliser
l'instruction FETCH, et tres certainement quelque chose comme une structure
de boucle sera necessaire dans votre programme pour traiter chaque ligne
retournee par la requete.
10. Que sont les relations? --C'est une autre question de conception...le
terme "relation" fait habituellement reference aux relations entre cles
primaires et externes entre les tables. Ce concept est important parce que,
quand les tables d'une base de donnees relationnelle sont concues, ces
relations doivent etre definies parce que cela determine quelles colonnes
sont ou ne sont pas des cles primaires ou externes. Vous avez peut-etre
entendu parler des diagrammes Entites-Relations, qui sont une
representation graphique des tables dans les schema de la base de donnees.
Voyez l'exemple de diagramme a la fin de cette section ou consultez
quelques sites indiques ci-dessous concernant ce sujet, car il y a de
nombreuses manieres de dessiner les diagrammes E-R. Mais d'abord, jetons
un oeil a chaque type de relation...
Une relation 1-a-1 (ou 1:1, ou 1-1) signifie que vous avez une colonne cle
primaire et que chaque cle primaire est en relation avec une cle externe.
Par exemple, dans le premier exemple, dans la table des adresses des
employes TableAdresseEmploye nous avons une colonne numero d'identification
de l'employe (EmployeeIDNo). Donc, la table TableAdresseEmploye est en
relation avec la table EmployeeStatisticsTable (deuxieme exemple de table)
par l'intermediaire du numero EmployeeIDNo. Plus precisement, chaque
employe, de la table TableAdresseEmploye possede des statistiques (une
ligne de donnees) dans la table EmployeeStatisticsTable. Meme si c'est un
exemple invente, c'est une relation "1-1". Inscrivez en caracteres gras le
"has" ("a" ou "possede")...quand on decrit une relation, il est important
de decrire une relation en utilisant un verbe.
Les deux autres types de relations peuvent ou pas utiliser une cle primaire
logique et des contraintes par rapport aux cles externes...cela depend
strictement des souhaits du concepteur. La premiere de ces relations est la
relation un-a-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 cle peuvent etre ajoutees au modele, ou eventuellement une
colonne d'identification peut etre utilisee pour etablir une relation. Un
exemple serait que pour chaque OwnerID dans la table AntiqueOwners, il y
ait un ou plusieurs (la valeur zero est egalement autorisee) articles
(Items) achetes dans la table ANTIQUES (verbe: acheter).
Finalement, la relation plusieurs-a plusieurs ("M-M") n'utilise
generalement pas de cles, 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 possibilite 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 donnees de fonctions, a avoir une
table possedant une ligne pour chaque employe et sa fonction, et d'avoir
une autre table contenant une ligne pour chaque fonction avec un des
employes l'occupant. Dans ce cas, vous auriez plusieurs lignes pour chaque
employe dans la premiere table, une pour chaque fonction, et plusieurs
lignes pour chaque fonction dans le seconde table, une pour chaque employe
ayant cette fonction.
Ces tables sont en relation M-M: chaque employe, dans la premiere table a
plusieurs fonctions dans la seconde table, et chaque fonction, dans la
seconde table, a plusieurs attributaires dans la premiere table. Ceci est
la partie emergee 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 simplifie de diagramme E-R.
[Exemple Simplifie de Diagramme Entites-Relations]
11. Quelles sont quelques unes des fonctionnalites importantes, non standard,
de SQL (Question extremement courante)? --Eh bien, nous allons voir ca dans
la section suivante...
----------------------------------------------------------------------------
SQL Non-standard..."A verifier pour votre site"
* INTERSECT et MINUS sont comme des instructions UNION , sauf que INTERSECT
produits des lignes qui apparaissent dans les deux requetes, et que MINUS
produit des lignes provenant de la premiere requete mais pas de la
seconde.
* Fonctionnalites de la Generation de Rapport: la clause COMPUTE est placee
a la fin d'une requete pour placer le resultat d'une fonction agregee a
la fin d'une liste, comme COMPUTE SUM (PRICE); Une autre solution est
d'utiliser une logique d'interruption: definir une interruption pour
diviser les resultats de la requete en groupes bases sur une colonne,
comme BREAK ON BUYERID. Alors, pour sortir un resultat apres la liste d'un
groupe, utilisez COMPUTE SUM OF PRICE ON BUYERID. Si, par exemple, vous
avez utilise ces trois clauses ("BREAK" en premier, "COMPUTE on break" en
second, "COMPUTE overall sum" en troisieme), vous obtiendrez un rapport qui
regroupera les articles par acheteurs, listera la somme de Prix pour chaque
groupe d'articles d'un acheteur, puis, apres que tous les groupes aient ete
listes, listera la somme de tous les Prix, le tout, avec des en-tetes et
des lignes generes par SQL.
* En plus des fonctions agregees indiquees ci-dessus, quelques SGBD ont des
fonctions supplementaires qui peuvent etre utilisees dans des listes de
selection (SELECT), sauf que ces fonctions (quelques fonctions caracteres
autorisent des resultats de plusieurs lignes) doivent etre utilisees avec
une valeur individuelle (pas de groupes), pour des requetes simple ligne.
De plus, les fonctions ne doivent etre utilisees qu' avec les types de
donnees appropries. Voici quelques Fonctions Mathematiques:
ABS(X) Valeur A-convertit les nombres negatifs en nombres positifs
et laisse les positifs inchanges
CEIL(X) X est une valeur decimale qui sera arrondie a la valeur
superieure.
FLOOR(X) X est une valeur decimale qui sera arrondie a la valeur
inferieure.
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 a la puissance Y.
ROUND(X,Y) Arrondit X a Y positions decimales. i Y n'est pas donne, X
est arrondi a 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 carree de X.
Fonctions Caracteres
LEFT(<string>,X)
Retourne les X caracteres les plus a gauche de la
chaine de caracteres.
RIGHT(<string>,X)
Retourne les X caracteres les plus a droite de la
chaine de caracteres.
UPPER(<string>)
Convertit tous les caracteres de la chaine en
majuscules.
LOWER(<string>)
Convertit tous les caracteres de la chaine en
minuscules.
INITCAP(<string>)
Convertit les caracteres initiaux de la chaine en
Capitales.
LENGTH(<string>)
Retourne le nombre de caracteres de la chaine.
<string>||<string>
Combine les deux chaines en une seule chaine,
concatenee, ou la premiere chaine est immediatement
suivie par la seconde.
LPAD(<string>,X,'*')
Insere des caracteres * (ou n'importe quel autre, mis
entre guillemets) a gauche de la chaine de
caracteres pour lui donner une longueur de X
caracteres.
RPAD(<string>,X,'*')
Insere des caracteres * (ou n'importe quel autre, mis
entre guillemets) a droite de la chaine de
caracteres pour lui donner une longueur de X
caracteres.
SUBSTR(<string>,X,Y)
Extrait Y lettres de la chaine a 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.
----------------------------------------------------------------------------
Resume de la Syntaxe--Pour Utilisateurs Avances Seulement
Voici la forme generale des instructions dont il a ete question dans ce
didacticiel, avec, en plus, quelques autres, (des explications sont donnees).
SOUVENEZ-VOUS que toutes ces instructions peuvent ne pas etre disponibles sur
votre systeme, aussi verifiez leur disponibilite 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 specifications(donnees, types, etc.) d'une colonne
existante;
cette instruction est egalement utilisee pour changer les specifications
physiques d'une table
(comment la table est stockee, etc.), mais ces definitions sont specifiques au
SGBD, aussi, lire la documentation. De meme, ces specifications physiques sont
utilisees avec les instructions de creation de table, lorsqu'une table est creee
pour la premiere fois. De plus, seulement une seule option peut etre executee
par instruction de modification: (Alter Table)--soit add (ajout), drop
(suppression), OU modify (modification) dans une simple instruction.
COMMIT; --rend les modifications effectuees sur une bases de donnees 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 parentheses.
CREATE TABLE <TABLE NAME>
(<COLUMN NAME> <DATA TYPE> [(<SIZE>)] <COLUMN CONSTRAINT>,
...autres colonnes); (valide egalement avec ALTER TABLE)
--ou SIZE est uniquement utilise avec certains types de donnees (voir
ci-dessus), et les contraintes incluent les possibilites suivantes (impose
automatiquement par le SGBD;
(un non respect entraine la generation d'une erreur) :
1. NULL ou NOT NULL (voir ci-dessus)
2. UNIQUE impose que deux lignes ne peuvent avoir la meme valeur pour cette
colonne
3. PRIMARY KEY indique a la base de donnees que cette colonne est la colonne
cle primaire (utilise uniquement si la cle est une colonne cle, autrement une
instruction
PRIMARY KEY (column, column, ...) apparait apres la derniere definition de
colonne.
4. CHECK permet de tester une condition quand on insere ou on met a jour une
donnee dans cette colonne; par exemple, CHECK (PRICE > 0) amene le systeme a
tester si la colonne Prix est superieure ou egale a zero avant d'accepter la
valeur...quelquefois implante comme instruction CONSTRAINT.
5. DEFAULT insere une valeur par defaut dans la base de donnees si l'on veut
inserer une ligne qui ne contienne pas de valeur pour cette colonne; par
exemple,
BENEFITS INTEGER DEFAULT = 10000
6. FOREIGN KEY fonctionne comme la Cle Primaire, mais est suivi par:
REFERENCES <TABLE NAME> (<COLUMN NAME>), qui fait reference a la cle primaire
de reference.
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 effectuees dans la base de donnees,
celles qui ont ete faites depuis la derniere 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]]; --ou 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 donnee, toutes les lignes
seront mises a jour selon l'instruction SET
----------------------------------------------------------------------------
Liens Importants
Liens Informatique & SQL/DB : Netscape -- Oracle -- Sybase -- Informix
--Microsoft
Page de Reference -- 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 Developpement -- 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'espere que vous aurez appris quelque chose de ce premier regard sur un langage
tres important qui est en train de devenir plus repandu dans le mode de
l'informatique client-serveur. J'ai redige cette page web pour apporter quelque
chose d'utile au web et a la communaute des utilisateurs du web. En realite,
j'ai appris que ce document est utilise dans plusieurs colleges pour des cours
sur les bases de donnees et par des chercheurs. En outre, lisez cette page dans
le nouveau livre, edite par Waite Publishing, sur Borland C++ Builder, qui sera
publie cet ete et dans une version a venir chez Sams Publishing. De plus, je
voudrais remercier tous les gens, sur les cinq continents, qui m'ont contactes
a propos de cette page.
J'espere aussi continuer a ajouter plus d'elements a ce didacticiel, tels que
des articles sur la conception d'une base de donnees et les extensions SQL non
standard, meme si je souhaite me tenir a l'ecart de particularites propres a
un Systeme de Gestion de Base de Donnee. Bonne chance pour vos developpements
en SQL et autres aventures informatiques.
Jim Hoffman
----------------------------------------------------------------------------
Commentaires ou Suggestions? Envoyez-moi un courrier electronique a jhoffman@one.net.
Ou vous pouvez desirer 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 etre utilise gratuitement
par n'importe quel utilisateur d'Internet, mais ne peut pas etre inclus dans
un autre document, publie sous une autre forme, ou produit en masse de quelque
facon que ce soit.
Netscape Navigator donne le meilleur affichage de cette page; celui-ci n'est pas
tres bon si l'on utilise Microsoft Internet Explorer.
Derniere mise a jour : 8-25-1997; ajout de quelques elements.
Chapitre suivant, Chapitre Précédent
Table des matières de ce chapitre, Table des matières générale
Début du document, Début de ce chapitre