39. Didacticiel SQL

Contenu de cette section

On peut trouver ce didacticiel SQL à http://w3.one.net/~jhoffman/sqltut.htm

Pour les commentaires ou suggestions, envoyer un courrier électronique à [email protected]

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 [email protected].

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