retour à la liste des howto linux Page suivante Page précédente Table des matières

297. Didacticiel SQL

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

Pour les commentaires ou suggestions, envoyer un courrier électronique à jhoffman@one.net

Vous pouvez également souhaiter jeter un oeil à http://w3.one.net/~jhoffman/index.html

John Hoffman suggère de visiter les sites suivants :

http://www.contrib.andrew.cmu.edu/~shadow/sql.htmlRéférence SQL

http://www.inquiry.com/techtips/thesqlpro/Demandez le Pro. de SQL

http://www.inquiry.com/techtips/thesqlpro/usefulsites.htmlSites utiles au Pro. du SGBD Relationnel SQL

http://infoweb.magi.com/~steve/develop.htmlLes Sites de sources du programmeur SGBD

http://info.itu.ch/special/wwwfiles Allez-y et regardez le fichier comp_db.html

http://www.compapp.dcu.ie/databases/f017.htmlIngrédients pour SGBD

http://www.stars.com/Tutorial/CGI/Création Web

http://wfn-shop.princeton.edu/cgi-bin/foldocDictionnaire d'Informatique

http://www-ccs.cs.umass.edu/db.htmlDBMS Lab/Liens

SQL FAQ http://epoch.CS.Berkeley.EDU:8000/sequoia/dba/montage/FAQ Allez-y et regardez le fichier SQL_TOC.html

http://chaos.mur.csu.edu.au/itc125/cgi/sqldb.htmlSGBD SQL

http://www.it.rit.edu/~wjs/IT/199602/icsa720/icsa720postings.htmlPage de Conception de Bases de Données RIT

http://www.pcslink.com/~ej/dbweb.htmlSite de liens vers des Bases de Données http://www.eng.uc.edu/~jtilley/tutorial.htmlDidacticiels de programmation sur le Web

http://www.ndev.com/ndc2/support/resources.htpRessources pour le Développement

http://ashok.pair.com/sql.htmListe de Requêtes

http://jazz.external.hp.com/training/sqltables/main.htmlIMAGE SQL Diverses

http://www.eit.com/web/netservices.htmlListe de Ressources Internet

Voici, ci-dessous, un extrait de la page d'accueil du didacticiel SQL.

Introduction au Langage de Requête Structuré

Version 3.31

Cette page contient un didacticiel du Langage de Requête Structuré( Structured
Query Language, également connu sous le nom de SQL). Ce didacticiel constitue
une nouveauté sur le World Wide Web, car c'est le premier didacticiel SQL
complet disponible sur l'Internet. SQL permet l'accès aux données dans les
systèmes  de gestion de bases de données relationnels tels que Oracle,
Sybase, Informix, Microsoft SQL Server, Access, et autres en permettant aux
utilisateurs de décrire les données qu'ils désirent obtenir. SQL permet aussi
aux utilisateurs de définir l'organisation des données dans la base et de les
manipuler. Le but de cette page est de décrire l'utilisation de SQL, et de
donner des exemples. C'est le langage ANSI SQL, ou standard SQL, qui sera
utilisé dans ce document. Il ne sera pas question ici des fonctionnalités
spécifiques à un SGBD particulier, qui seront traitées dans la section "SQL
non-standard". Nous vous recommandons d'imprimer cette page afin de pouvoir
vous référer facilement aux différents exemples.
----------------------------------------------------------------------------
Table des matières

     Principes fondamentaux de l'instruction SELECT
     Sélection Conditionnelle
     Opérateurs Relationnels
     Conditions Composées
     IN & BETWEEN
     Utilisation de LIKE

     Jointures
     Clés
     Réalisation d'une Jointure
     Elimination des Doubles
     Alias & In/Sous-requêtes

     Fonctions d'Agrégation
     Vues
     Création de Nouvelles Tables
     Modification des Tables
     Ajout de Données
     Suppression de Données
     Mise à Jour des Données

     Index
     GROUP BY & HAVING
     Sous-requêtes Supplémentaires
     EXISTS & ALL
     UNION & Jointures Externes
     SQL Intégré
     Questions Courantes sur SQL
     SQL Non-standard
     Résumé de la Syntaxe
     Liens Importants

----------------------------------------------------------------------------
Principes fondamentaux de l'instruction SELECT

Dans une base de données relationnelle, les données sont stockées dans des
tables. Par exemple,  une table pourrait mettre en relation le Numéro de
Sécurité Sociale, le Nom et l'Adresse:

                        TableAdresseEmploye

 NSS      Prenom    Nom       Addresse        Ville       Etat
 512687458Joe       Smith     83 First Street Howard      Ohio
 758420012Mary      Scott     842 Vine Ave.   LosantivilleOhio
 102254896Sam       Jones     33 Elm St.      Paris       New York
 876512563Sarah     Ackerman  440 U.S. 110    Upton       Michigan

Maintenant, supposons que nous voulions obtenir l'adresse de chaque employé.
On utilisera SELECT, comme ceci :

SELECT Prenom, Nom, Adresse, Ville, Etat
FROM TableAdresseEmploye;

Voici le résultat de l'interrogation de notre base de données :

 Prenom    Nom        Adresse         Ville        Etat
 Joe       Smith      83 First Street  Howard       Ohio
 Mary      Scott      842 Vine Ave.    Losantiville Ohio
 Sam       Jones      33 Elm St.       Paris        New York
 Sarah     Ackerman   440 U.S. 110     Upton        Michigan

Explication de ce que l'on vient de faire : on vient de rechercher dans toutes
les données de la table TableAdresseEmploye les colonnes nommées Prenom, Nom,
Adresse, Ville et Etat. Noter que les noms de colonnes et les noms de tables
sont sans espaces... ils doivent être saisis en un seul mot; et que
l'instruction se termine par un point-virgule (;). La forme générale d'une
instruction SELECT, qui permet de retrouver toutes les lignes d'une table
est :

SELECT NomColonne, NomColonne, ...
FROM NomTable;

Pour obtenir toutes les colonnes d'une table sans avoir à taper tous les noms
de colonne, utiliser :

SELECT * FROM NomTable;

Chaque Système de Gestion de Base de Données (SGBD) et chaque logiciel de
base de données utilisent différentes méthodes pour se connecter à la base
de donnée et pour entrer les instructions SQL; consultez le "guru" de votre
ordinateur pour qu'il vous aide à vous connecter de façon à pouvoir utiliser
SQL.
----------------------------------------------------------------------------
Sélection Conditionnelle

Pour étudier plus avant l'instruction SELECT , jetons un oeil à un nouvel exemple de table
(exemple uniquement hypothétique) :

                      EmployeeStatisticsTable

 EmployeeIDNo      Salary           Benefits         Position
 010               75000            15000            Manager
 105               65000            15000            Manager
 152               60000            15000            Manager
 215               60000            12500            Manager
 244               50000            12000            Staff
 300               45000            10000            Staff
 335               40000            10000            Staff
 400               32000            7500             Entry-Level
 441               28000            7500             Entry-Level

----------------------------------------------------------------------------
Opérateurs Relationnels

Il y a six Opérateurs Relationnels en SQL, et, après les avoir présentés,
nous verrons comment les utiliser :

 =            Egal
 <> or !=
 (voir le manuel) Différent
 <            Plus Petit Que
 >            Plus Grand Que
 <=           Plus Petit Que ou Egal à

 >=           Plus Grand Que ou Egal à

La clause WHERE est utilisée pour spécifier que l'on affichera seulement
certaines ligne de la table, selon un critère définit par cette clause WHERE.
Ce sera plus clair en prenant une paire d'exemples.

Si l'on désire voir les numéros d'identification des employés (EMPLOYEEIDNO)
dont le salaire est égal ou supérieur à 50 000, on utilisera la requête
suivante :

SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE SALARY >= 50000;

Noter que le symbole >= (plus grand que ou égal à) est utilisé, puisque l'on
désire voir tout ceux qui gagnent plus de 50 000, ou 50 000, sur la même
liste. On aura l'affichage :

EMPLOYEEIDNO
------------
010
105
152
215
244

La description de WHERE, SALARY >= 50000, est appelée une condition. On pourrait
effectuer le même traitement sur des colonnes de texte :

SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION = 'Manager';

Ceci entraînera l'affichage des Numéros d'Identification de tous les Managers.
En général, avec les colonnes contenant du texte, n'utiliser que égal à ou
différent de, et assurez vous que tout texte apparaissant dans l'instruction
est entouré d'apostrophes (').

----------------------------------------------------------------------------
Conditions plus complexes: Conditions Composées

L'opérateur AND (ET) combine deux ou plusieurs conditions et n'affiche une
ligne que si cette ligne satisfait TOUTES les conditions requises (i.e. où
toutes les conditions sont réalisées). Par exemple, pour afficher tout le
personnel gagnant plus 40 000, écrire :

SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE SALARY > 40000 AND POSITION = 'Staff';

L'opérateur OR (OU) combine deux ou plusieurs conditions mais retourne cette
ligne si N'IMPORTE LAQUELLE des conditions requises est remplie. Pour
visualiser tous ceux qui gagnent moins de 40 000 ou qui reçoivent moins de 10
000 en participation aux bénéfices, utilisez la requête suivante :

SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE SALARY < 40000 OR BENEFITS < 10000;

Les opérateurs AND et OR peuvent être combinés, par exemple :

SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION = 'Manager' AND SALARY > 60000 OR BENEFITS > 12000;

En premier lieu, SQL recherche les lignes pour lesquelles la valeur de la
colonne salaire est supérieure à 60 000 et celle de position est égale à
Manager, puis, à partir de cette liste de lignes, SQL recherche alors celles
qui satisfont à la condition AND (ET) précédente ou à la condition spécifiant
que la colonne Indemnités est supérieure à  12 000. En conséquence, SQL n'affiche
seulement que cette seconde liste de lignes, en gardant à l'esprit que tous ceux
dont les Indemnités sont supérieures à 12 000 en feront partie puisque l'opérateur
OR (OU) inclue la ligne si l'une des conditions est vérifiée. Notez en passant
que l'opération AND (ET) est effectuée en premier.

Pour généraliser ce processus, SQL effectue l(es) opération(s) AND pour déterminer
les lignes ou l(es) opération(s) AND sont vérifiées (souvenez-vous bien : toutes
les conditions sont vérifiées), puis ces résultats sont utilisés pour tester les
conditions OR, et, ne seront affichées que les lignes où les conditions requises
par l'opérateur OR seront vérifiées.

Pour que les OR's soient effectués avant les AND's, par exemple si vous vouliez voir
une liste des employés dont le salaire est élevé (>50 000) OU bénéficiant d'indemnités
importantes (>10 000), ET qui soient cadres, utilisez des parenthèses :

SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION = 'Manager' AND (SALARY > 50000 OR BENEFIT > 10000);

----------------------------------------------------------------------------
IN et BETWEEN

Une méthode plus facile pour utiliser les conditions composées consiste à utiliser
IN ou BETWEEN. Par exemple, si vous désirez une liste des cadres et du personnel :

SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION IN ('Manager', 'Staff');

ou une liste de ceux dont le salaire est supérieur ou égal à 30 000, mais inférieur
ou égal à 50 000, utilisez:

SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE SALARY BETWEEN 30000 AND 50000;

Pour obtenir la liste de ceux qui n'entrent pas dans ces critères, essayez :

SELECT EMPLOYEEIDNO
FROM EMPLOYEESTATISTICSTABLE
WHERE SALARY NOT BETWEEN 30000 AND 50000;

De la même façon, NOT IN donne la liste de toutes les lignes exclues de la liste
obtenue par l'opérateur IN.

----------------------------------------------------------------------------
Utilisation de LIKE

Regardons la table EmployeeStatisticsTable, et disons que l'on veut voir tous les
gens dont le nom commence par "L"; essayons :

SELECT EMPLOYEEIDNO
FROM EMPLOYEEADDRESSTABLE
WHERE LASTNAME LIKE 'L%';

Le signe pourcentage (%) est utilisé pour représenter n'importe quel caractère
possible (nombre, lettre, ou signe de ponctuation) ou ensemble de caractères
qui peut apparaître après le "L". Pour trouver les gens dont le Nom se termine
avec "L", utiliser '%L', ou si vous désirez le "L" au milieu du mot, essayez
'%L%'. Le symbole '%' peut être utilisé pour n'importe quel caractère, et
dont la position est relative par rapport à des caractères donnés. NOT LIKE
affiche les lignes qui ne correspondent pas à la description donnée. Il y a
d'autres manières d'utiliser LIKE, de même que n'importe lesquelles des
conditions composées dont nous venons de parler, bien que cela dépende du SGBD
que vous utilisez; comme d'habitude, consultez un manuel ou le gestionnaire ou
administrateur de votre système pour en connaître les fonctionnalités, ou
simplement, assurez vous que ce que vous essayer de faire est possible et
autorisé. Cet avertissement est aussi valable pour les fonctionnalités de SQL
exposées ci-dessous. Cette section est donnée à titre d'exemple des requêtes
qui peuvent être écrites en SQL.
----------------------------------------------------------------------------
Jointures

Dans cette section, nous allons parler uniquement des jointures internes et
des equi-jointures, dans la mesure où ce sont les plus utiles. Pour avoir plus
d'informations, voyez les liens sur des sites SQL au bas de cette  page.

On suggère qu'une bonne manière de concevoir une base de données implique que
chaque table ne contienne des données qui ne concernent qu'une seule entité,
et que des informations détaillées peuvent être obtenues, dans une base de
données relationnelle, en utilisant des tables supplémentaires et en effectuant
une jointure.

Premièrement, jetons un oeil à ces exemples de tables :

            AntiqueOwners

 OwnerIDOwnerLastName OwnerFirstName
 01     Jones         Bill
 02     Smith         Bob
 15     Lawson        Patricia
 21     Akins         Jane
 50     Fowler        Sam

---------------------------------------------------------

       Orders

 OwnerIDItemDesired
 02     Table
 02     Desk
 21     Chair
 15     Mirror

--------------------------------------

           Antiques

 SellerIDBuyerID Item
 01      50      Bed
 02      15      Table
 15      02      Chair
 21      50      Mirror
 50      01      Desk
 01      21      Cabinet
 02      21      Coffee Table
 15      50      Chair
 01      15      Jewelry Box
 02      21      Pottery
 21      02      Bookcase
 50      01      Plant Stand

----------------------------------------------------------------------------
Clés

En premier lieu, nous allons parler du concept de clés. Une clé primaire est
une colonne ou en ensemble de colonnes qui identifie de manière unique les
autres données d'une ligne donnée. Par exemple, dans la table AntiqueOwners,
la colonne OwnerID identifie de manière unique cette ligne. Ceci signifie deux
choses: que deux lignes ne peuvent avoir le même OwnerID, et que, même si
deux propriétaires les mêmes noms et prénoms la colonne OwnerID garantit que
ces deux propriétaires ne seront pas confondus l'un avec l'autre, puisque la
colonne OwnerID unique sera utilisée à travers la base de données pour se
référer à un propriétaire, plutôt que son nom.

Une clé externe est une colonne d'une table qui est clé primaire d'une autre
table, ce qui signifie que toutes les données d'une clé externe doivent avoir
des données correspondantes dans l'autre table, où cette colonne est la clé
primaire.
Pour parler SGBD, cette correspondance est connue sous le nom d'intégré
référentielle. Par exemple, dans la table Antiques, BuyerID et SellerID sont
tous les deux des clés externes à la clé primaire de la table AntiqueOwners
(OwnerID; pour les besoins de notre argumentation, on doit d'abord être
référencé dans la table AntiqueOwners avant de pouvoir acheter ou vendre quoi
que ce soit), puisque, dans les deux tables, les colonnes ID sont utilisées
pour identifier les propriétaires, les acheteurs ou les vendeurs, et que
OwnerID est la clé primaire de la table AntiqueOwners. En d'autres termes,
toutes ces données "ID" sont utilisées pour se référer aux propriétaires,
acheteurs et vendeurs sans avoir à utiliser les noms effectifs.

----------------------------------------------------------------------------
Réalisation d'une jointure

Le but de ces clés est ainsi de pouvoir mettre en relation les données à
travers les tables sans avoir à répéter les données dans chaque tables,
--c'est toute la puissance des bases de données relationnelles. Par exemple,
on peut trouver les noms de ceux qui ont acheté une chaise sans avoir à lister
la totalité du nom de l'acheteur dans la table Antiques... vous pouvez trouver
ce nom en mettant en relation ceux qui ont acheté une chaise avec les noms
dans la table AntiqueOwners en utilisant le OwnerID, qui met en relation les
données dans les deux tables. Pour trouver les noms de ceux qui ont acheté
une chaise, utilisez la requête suivante :

SELECT OWNERLASTNAME, OWNERFIRSTNAME
FROM ANTIQUEOWNERS, ANTIQUES
WHERE BUYERID = OWNERID AND ITEM = 'Chair';

Notez ce qui suit au sujet de cette requête... notez que les deux tables mise
en jeux dans cette relation sont listées dans la clause FROM de l'instruction.
Dans la clause WHERE, notez, en premier lieu, que la partie ITEM = 'Chair' de
la clause limite la liste à ceux qui ont acheté (et, dans cet exemple, de ce
fait possèdent) une chaise. En second lieu, notez comment les colonnes ID sont
mises en relation d'une table à la suivante par l'utilisation de la clause
BUYERID = OWNERID. Ne seront listés que les noms  de la table AntiqueOwners
dont les ID correspondent à travers les tables et dont l'article acheté est
une chaise (à cause du AND). Parce que la condition de jointure utilisée est
un signe égal, cette jointure est appelée une équi-jointures. le résultat de
cette requête donnera deux noms: Smith, Bob et Fowler, Sam.

La notation avec un point (.) fait référence à l'utilisation du nom de colonne
en suffixe du nom de table pour éviter toute ambiguïté, comme par exemple:

SELECT ANTIQUEOWNERS.OWNERLASTNAME, ANTIQUEOWNERS.OWNERFIRSTNAME
FROM ANTIQUEOWNERS, ANTIQUES
WHERE ANTIQUES.BUYERID = ANTIQUEOWNERS.OWNERID AND ANTIQUES.ITEM = 'Chair';

Cependant, puisque les noms de colonnes sont différents dans chaque table,
cela n'était pas nécessaire.

----------------------------------------------------------------------------
DISTINCT et l'Elimination des Doubles

Disons que vous ne vouliez seulement que la liste des Identificateurs (ID) et
des noms des gens qui ont vendu une antiquité. Evidemment, vous ne désirez
une liste où chaque vendeur n'apparaît qu'une fois--vous ne voulez pas savoir
combien d'antiquités ont été vendues par une personne, mais uniquement le fait
que cette personne en a vendu une (pour les comptages, voir la fonction
d'Agrégation ci-dessous). Cela signifie qu'il vous faudra dire à SQL d'éliminer
les doubles des lignes des ventes, et de ne seulement lister chaque personne
qu'une fois. Pour réaliser cela, utilisez le mot-clé DISTINCT.

Premièrement, vous aurez besoin de faire un équi-jointures sur la table
AntiqueOwners pour obtenir les données concernant le Nom et le Prénom de la
personne. Cependant, gardez à l'esprit que, puisque la colonne SellerID dans
la table Antiques est une clé externe de la table AntiqueOwners, un vendeur
ne sera listé que s'il y a une ligne dans la table AntiqueOwners contenant les
ID et les noms. Nous voulons également éliminer les multiples occurrences du
SellerID dans notre liste, donc, nous utiliserons le mot-clé DISTINCT pour les
colonnes où les répétitions peuvent se produire.

Pour ajouter une difficulté, nous voulons aussi que cette liste soit classée
par ordre alphabétique des Noms, puis des Prénoms (à l'intérieur des noms),
puis des  OwnerID (à l'intérieur des noms et des prénoms). Pour cela, nous
utiliserons la clause ORDER BY :

SELECT DISTINCT SELLERID, OWNERLASTNAME, OWNERFIRSTNAME
FROM ANTIQUES, ANTIQUEOWNERS
WHERE SELLERID = OWNERID
ORDER BY OWNERLASTNAME, OWNERFIRSTNAME, OWNERID;

Dans cet exemple, puisque tout le monde a vendu un article, nous aurons une
liste de tous les propriétaires, classés par ordre alphabétique sur les noms.
Pour référence ultérieure (au cas où quelqu'un le demande), ce type de jointure
est considéré comme appartenant à la catégorie des jointures internes.

----------------------------------------------------------------------------
Alias et In/Sous-requêtes

Dans cette section, nous parlerons des Alias, In et de l'utilisation des
sous-requêtes, et de la manière de les utiliser dans un exemple de 3-table.
En premier lieu, regardez cette requête qui imprime le nom des propriétaires
qui ont passé une commande et la nature de cette commande, en ne listant
seulement que les commandes qui peuvent être satisfaites (c'est à dire qu'il
y a un vendeur qui possède l'article commandé) :

SELECT OWN.OWNERLASTNAME Last Name, ORD.ITEMDESIRED Item Ordered
FROM ORDERS ORD, ANTIQUEOWNERS OWN
WHERE ORD.OWNERID = OWN.OWNERID
AND ORD.ITEMDESIRED IN

     (SELECT ITEM
     FROM ANTIQUES);

Ce qui donne :

Last name Item Ordered
--------- ------------
Smith     Table
Smith     Desk
Akins     Chair
Lawson    Mirror

Il y a plusieurs choses à noter à propos de cette requête :

  1. Tout d'abord, les mots "Last Name" et "Item Ordered" dans les lignes
     SELECT donnent les en-têtes du rapport.
  2. Les mots OWN et ORD sont des alias; ce sont de nouveaux noms pour les
     deux tables données dans la clause FROM qui sont utilisés comme préfixes
     pour toutes les notations point (.) de noms de colonnes dans les requêtes
     (voir ci-dessus). Ceci élimine les risques ambiguïté, spécialement dans
     l'équi-jointure de la clause WHERE où les deux tables ont une colonne
     nommée OwnerID, et cette notation point (.) précise à SQL que nous
     désignons deux OwnerID différents de deux tables différentes.
  3. Notez que la table des commandes (ORDERS) est indiquée la première dans
     la clause FROM; ceci apporte la certitude que la liste sera réalisée à
     partir de cette table, et que la table AntiqueOwners
     est utilisée uniquement pour obtenir les informations détaillées (Last
     Name / Nom).
  4. Plus important, la clause AND dans la clause WHERE (OU) force l'utilisation
     de la Sous-requête  In ("= ANY" ou "= SOME" sont deux utilisations
     équivalentes de IN). Cela entraîne que la sous-requête est effectuée,
     retournant une liste de tous les articles (Items) appartenant à la table
     Antiques, comme s'il n'y avait pas de clause WHERE (OU). Donc, pour lister
     une ligne de la table ORDERS, le ItemDesired (article_désiré) doit être
     dans la liste retournée des articles appartenant à la table Antiques, et
     donc un article ne sera listé que si la commande ne peut être honorée
     que par un autre propriétaire. On peut se le représenter comme ceci: la
     sous-requête retourne un ensemble d'articles (Items) auquel chaque
     ItemDesired (Article_Désiré) dans la table des commandes (ORDERS) est
     comparé; la condition IN (DANS) n'est vraie que si le ItemDesired
     appartient à l'ensemble provenant de la table ANTIQUES.
  5. Notez également, comme c'est le cas ici, qu'il y a un objet ancien pour
     chaque demande, ce qui, évidemment, n'est pas toujours le cas... De plus,
     notez aussi que, lorsque  IN, "= ANY", ou "= SOME" est utilisé, ces
     mots-clés font référence à toutes les lignes qui conviennent, pas aux
     colonnes... c'est à dire que vous ne pouvez pas mettre de multiples
     colonnes dans un clause SELECT de sous-requête, pour tenter de faire
     correspondre la colonne de la clause WHERE externe avec l'une des
     multiples valeurs de colonnes possibles de la sous-requête; une seule
     colonne peut être indiquée dans la sous-requête, et la correspondance
     possible provient de multiples valeurs de lignes, dans cette colonne
     unique, et non pas l'inverse.

Ouf! Ce sera tout sur ce sujet des requêtes SELECT complexes pour l'instant.
Maintenait, voyons d'autres instructions SQL.
----------------------------------------------------------------------------
Instructions SQL Diverses

Fonctions d'Agrégation

Je parlerai de cinq fonctions d'agrégation importantes: SUM, AVG, MAX, MIN, et
COUNT. On les appelle fonctions d'agrégation parce qu'elles résument les
résultats d'une requête, plutôt que de donner une liste de toutes les lignes.

   * SUM () donne la somme, pour une colonne donnée, de toutes les lignes qui
satisfont aux conditions requises, et où la colonne donnée est numérique.
   * AVG () donne la moyenne de la colonne donnée.
   * MAX () donne la plus grande valeur dans la colonne donnée.
   * MIN () donne la plus petite valeur dans la colonne donnée.
   * COUNT(*) donne le nombre de lignes qui satisfont aux conditions.

En utilisant les tables du début de ce document, regardons trois exemples :

SELECT SUM(SALARY), AVG(SALARY)
FROM EMPLOYEESTATISTICSTABLE;

Cette requête donne la somme des de salaires tous les salariés présents dans
la table et le salaire moyen.

SELECT MIN(BENEFITS)
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION = 'Manager';

Cette requête donne le chiffre de la colonne indemnités le plus faible des
employés qui sont Managers, cette valeur est 12 500.

SELECT COUNT(*)
FROM EMPLOYEESTATISTICSTABLE
WHERE POSITION = 'Staff';

Cette requête vous donne le nombre d'employés ayant le statut de cadre (Staff,
i.e. 3).

----------------------------------------------------------------------------
Les Vues

En SQL, vous pouvez (vérifiez auprès de votre Administrateur de Base de Données,
DBA) avoir accès à la création de vues par vous-même. Une vue vous permet d'affecter
les résultats d'une requête à une nouvelle table personnelle, que vous pourrez
utiliser dans d'autres requêtes, pour laquelle vous donnez le nom de la vue dans
votre clause FROM. Quand vous accédez à une vue, la requête qui est définie dans
l'instruction de création de la vue est effectuée (généralement), et les résultats
de cette requête ont la même allure qu'une autre table dans la requête que vous
avez écrit en invoquant la vue. Par exemple, pour créer une vue :

CREATE VIEW ANTVIEW AS SELECT ITEMDESIRED FROM ORDERS;

Maintenant, écrivons une requête utilisant cette vue comme une table, où la
table est seulement une liste de tous les articles désirés (ITEMDESIRED) de
la table ORDERS :

SELECT SELLERID
FROM ANTIQUES, ANTVIEW
WHERE ITEMDESIRED = ITEM;

Cette table montre tous les Identifiants de Vendeurs (SellerID) de la table
ANTIQUES où l'article (Item) dans cette table apparaît dans la vue ANTVIEW,
qui consiste justement en tous les Articles Désirés (Items Desired) dans la
table ORDERS. La liste est crée en parcourant les articles AntiquesItems un
par un jusqu'à ce qu'il y ait correspondance avec la vue ANTVIEW. Les vues
peuvent être utilisées pour restreindre les accès à la base de données,
ainsi que, dans ce cas, pour simplifier une requête complexe.

----------------------------------------------------------------------------
Création de Nouvelles Tables

Toutes les tables, dans une base de données doivent être créées à un certain
moment... voyons comment mous pourrions créer la table des commandes (ORDERS) :

CREATE TABLE ORDERS
(OWNERID INTEGER NOT NULL,
ITEMDESIRED CHAR(40) NOT NULL);

Cette instruction donne un nom à la table et renseigne le SGBD sur la nature
de chaque colonne de la table. Veuillez noter que cette instruction utilise
des types de données génériques, et que les types de données peuvent être
différents, selon le SGBD que vous utilisez. Comme d'habitude, vérifiez vos
conditions locales. Voici quelques types de données génériques courants:

   * Char(x) - Une colonne de caractères, où x est un nombre indiquant le
     nombre maximum de caractères permis (taille maximale) de la colonne.
   * Integer - Une colonne de nombres entiers, positifs ou négatifs.
   * Decimal(x, y) - Une colonne de nombre décimaux, où x est la taille
     maximum, en digits, des nombres décimaux dans cette colonne, et y le
     nombre maximal de digits autorisés après la virgule. Le nombre maximal
     (4,2) sera 99.99.
   * Date - Une colonne de date dans un format spécifique au SGBD.
   * Logical - Une colonne qui ne peut contenir que deux valeurs: VRAI ou FAUX.

Autre remarque, l'indication NOT NULL (non nul) signifie que la colonne doit
avoir une valeur pour chacune des lignes. Si l'on avait utilisé NULL (nul),
cette colonne peut être laissée vide dans certaines lignes.

----------------------------------------------------------------------------
Modification des tables

Ajoutons une colonne à la table ANTIQUES pour permettre la saisie du prix d'un
article donné :

ALTER TABLE ANTIQUES ADD (PRICE DECIMAL(8,2) NULL);

On verra plus tard comment les données pour cette nouvelle colonne peuvent
être mises à jour ou ajoutées.

----------------------------------------------------------------------------
Ajout de Données

Pour insérer des lignes dans une table, faites ce qui suit :

INSERT INTO ANTIQUES VALUES (21, 01, 'Ottoman', 200.00);

Ceci insère les données dans la table, en tant que nouvelle ligne, colonne
par colonne, dans un ordre prédéfinit. Au lieu de cela, changeons cet ordre
et laissons le Prix vide:

INSERT INTO ANTIQUES (BUYERID, SELLERID, ITEM)
VALUES (01, 21, 'Ottoman');

----------------------------------------------------------------------------
Suppression de données

Supprimons cette nouvelle ligne de la base de données :

DELETE FROM ANTIQUES
WHERE ITEM = 'Ottoman';

Mais s'il y a une autre ligne qui contient 'Ottoman', cette ligne sera
également supprimée. Supprimons toutes les lignes (une, dans ce cas) qui
contient les données spécifiques que nous avons ajouté plus
 tôt :

DELETE FROM ANTIQUES
WHERE ITEM = 'Ottoman' AND BUYERID = 01 AND SELLERID = 21;

----------------------------------------------------------------------------
Mise à Jour des Données

Mettons un Prix à jour dans une ligne qui n'en contient pas encore :

UPDATE ANTIQUES SET PRICE = 500.00 WHERE ITEM = 'Chair';

Ceci met le Prix de toutes les Chaises (Chair) à 500.00. Comme indiqué
ci-dessus, conditions WHERE supplémentaires, utilisation de AND, il faut
utiliser ces conditions pour limiter la mise à jour à des lignes spécifiques.
De plus, des colonnes supplémentaires peuvent être renseignées en séparant
les instructions "égal" par des virgules.

----------------------------------------------------------------------------
Considérations Diverses

Index

Les Index permettent à un SGBD d'accéder au données plus rapidement (veuillez
noter que cette fonctionnalité est non-standard/indisponible sur certains
systèmes). Le système crée une structure de donnée interne (l'index) qui
entraîne une sélection de lignes beaucoup plus rapide, quand la sélection
est basée sur des colonnes indexées. Cet index indique au SGBD où se trouve
une certaine ligne dans une table étant donné une valeur de colonne indexée,
exactement comme l'index d'un livre vous indique à quelle page un mot donné
se trouve. Créons un index pour le OwnerID dans la colonne AntiqueOwners :

CREATE INDEX OID_IDX ON ANTIQUEOWNERS (OWNERID);

Maintenant sur les noms:

CREATE INDEX NAME_IDX ON ANTIQUEOWNERS (OWNERLASTNAME, OWNERFIRSTNAME);

Pour être débarrassé d'un index, supprimez le :

DROP INDEX OID_IDX;

A propos, vous pouvez aussi bien "supprimer" une table (attention!--cela
signifie que votre table est détruite). Dans le second exemple, l'index est
construit à partir des deux colonnes, agrégées ensembles--un comportement
bizarre peut résulter de cette situation... vérifiez dans votre manuel avant
d'effectuer une telle opération.

Quelques SGBD n'imposent pas l'utilisation de clés primaires; en d'autres
termes, l'unicité d'une colonne n'est pas imposée automatiquement. Cela
signifie que, par exemple, j'aurais pu essayer d'insérer une autre ligne
dans la table  AntiqueOwners avec un OwnerID de 02, quelques systèmes me
permettent de faire cela, bien qu'il ne le faille pas, puisque cette colonne
est supposée être unique dans cette table (chaque valeur de ligne est supposée
être différente). Une manière de contourner cela est de créer un index unique
sur la colonne que nous souhaitons voir être la clé primaire pour forcer le
système à interdire les doubles :

CREATE UNIQUE INDEX OID_IDX ON ANTIQUEOWNERS (OWNERID);

----------------------------------------------------------------------------
GROUP BY et HAVING

Une utilisation spéciale de la clause GROUP BY est l'association d'une fonction
agrégée (spécialement COUNT; qui compte le nombre de lignes dans chaque groupe)
avec des groupes de lignes. Premièrement, supposons que la table ANTIQUES
possède la colonne Prix (Price)t, et que chaque ligne contienne une valeur
dans cette colonne. Nous voulons voir le prix de l'article le plus cher acheté
par chaque propriétaire. Il nous faut donc dire à SQL de grouper les achats de
chacun des propriétaires, et de nous dire le prix d'achat maximum :

SELECT BUYERID, MAX(PRICE)
FROM ANTIQUES
GROUP BY BUYERID;

Maintenant, disons que nous ne voulons voir que le prix maximum si l'achat
dépasse 1000, nous devrons utiliser la clause HAVING :

SELECT BUYERID, MAX(PRICE)
FROM ANTIQUES
GROUP BY BUYERID
HAVING PRICE > 1000;

----------------------------------------------------------------------------
Sous-requêtes Supplémentaires

Un autre usage commun des sous-requêtes amène à l'utilisation des opérateurs
pour permettre à une condition WHERE d'inclure la sortie SELECT d'une
sous-requête. En premier, demandons la liste des acheteurs ayant acheté un
article cher (le prix de cet article est supérieur de 100 au prix moyen de tous
les articles achetés) :

SELECT OWNERID
FROM ANTIQUES
WHERE PRICE >

     (SELECT AVG(PRICE) + 100
     FROM ANTIQUES);

La sous-requête calcule le Prix moyen, ajoute 100, et, et en utilisant ce
chiffre on imprime un OwnerID pour chaque article coûtant plus que ce chiffre.
On peut utiliser DISTINCT OWNERID, pour éliminer les doubles.

Listons les Noms (Last Names) de ceux qui sont dans la table AntiqueOwners,
SEULEMENT s'ils ont acheté un article :

SELECT OWNERLASTNAME
FROM ANTIQUEOWNERS
WHERE OWNERID =

     (SELECT DISTINCT BUYERID
     FROM ANTIQUES);

Cette sous-requête retourne une liste des acheteurs, et le Nom du propriétaire
d'un objet ancien est imprimé seulement si l'identificateur du Propriétaire
(Owner's ID) dans la liste obtenue par la sous-requête (appelée quelquefois
liste des candidats).

Voici un exemple de mise à jour: nous savons que la personne qui a acheté la
bibliothèque a un Prénom erroné dans la base de données... Ce devrait être
John :

UPDATE ANTIQUEOWNERS
SET OWNERFIRSTNAME = 'John'
WHERE OWNERID =

     (SELECT BUYERID
     FROM ANTIQUES
     WHERE ITEM = 'Bookcase');

Tout d'abord, la sous-requête trouve le BuyerID pour la (les) personne(s) qui
a (ont) acheté(s) la bibliothèque, puis la requête externe met à jour son
Prénom.

Souvenez vous de cette règle à propos des sous-requêtes: quand vous avez une
sous-requête faisant partie d'une condition WHERE, la clause SELECT dans la
sous-requête doit avoir des colonnes qui correspondent en nombre et en type
à celle de la clause WHERE de la requête externe. En d'autres termes, si vous
avez "WHERE ColumnName = (SELECT...);", le SELECT ne peut faire référence qu'à
une seule colonne, pour pouvoir correspondre à la clause WHERE externe, et
elles doivent être du même type (les deux étant soit entiers, soit chaînes
de caractères, etc.).

----------------------------------------------------------------------------
EXISTS et ALL

EXISTS utilise une sous-requête comme condition, où cette condition est Vraie
si la sous-requête retourne au moins une ligne et Fausse si la sous-requête
n'en retourne aucune; c'est une fonctionnalité qui n'est pas intuitive et
n'est utilisée que dans peu de cas. Cependant, si un client éventuel voulait
consulter la liste des propriétaires pour voir s'il y a des chaises (Chairs),
essayez :

SELECT OWNERFIRSTNAME, OWNERLASTNAME
FROM ANTIQUEOWNERS
WHERE EXISTS

     (SELECT *
     FROM ANTIQUES
     WHERE ITEM = 'Chair');

S'il y a des Chaises (Chair) dans une colonne de la table ANTIQUES, la
sous-requête renverra une ou plusieurs lignes, rendant la clause EXISTS
vraie, ce qui amènera SQL à donner une liste des propriétaires dans
ANTIQUEOWNERS. S'il n'y avait eu aucune Chaise, la requête externe n'aurait
pas renvoyé de ligne.

ALL est une autre fonctionnalité peu commune, et en général, on peut réaliser
une requête avec ALL de manières différentes et éventuellement plus simples;
regardons cet exemple de requête :

SELECT BUYERID, ITEM
FROM ANTIQUES
WHERE PRICE >= ALL

     (SELECT PRICE
     FROM ANTIQUES);

Ceci va nous retourner l'article de prix le plus élevé (ou plus d'un article
s'il y a des ex-aequo), et son acheteur. La sous-requête renvoie la liste de
tous les Prix (PRICE) dans la table ANTIQUES, puis la requête externe examine
chaque ligne de la table ANTIQUES et si son Prix est supérieur ou égal à chacun
(ou ALL, TOUS) des Prix de cette liste, il est affiché, donnant ainsi l'article
de prix le plus élevé. La raison pour laquelle ">=" doit être utilisé est que
l'article de prix le plus élevé sera égal au prix le plus élevé, puisque cet
Article est dans la liste de Prix.

----------------------------------------------------------------------------
UNION et Jointure Externe

Il y a des occasions  où vous pouvez désirer voir ensembles les résultats de
requêtes multiples, leurs sorties étant combinées; pour cela utilisez UNION.
Pour fusionner la sortie des deux requêtes suivantes, en affichant l'identificateur
de tous les Acheteurs plus tous ceux qui ont passé une Commande :

SELECT BUYERID
FROM ANTIQUEOWNERS
UNION
SELECT OWNERID
FROM ORDERS;

Il faut noter que SQL nécessite que les types de données des listes des clauses
SELECT correspondent colonne par colonne. Dans cet exemple, les identificateurs
BuyerID et OwnerID sont du même type (entier). Notez également que SQL
effectue automatiquement une élimination des doubles quand on utilise la clause
UNION (comme si c'étaient deux "ensembles"); dans une requête simple, il faut
utiliser la clause DISTINCT.

La jointure externe est utilisée quand une requête de jointure est "unifiée",
les lignes n'étant pas incluses dans la jointure. Ceci est particulièrement
utile si des "balises" de type constante texte sont inclus. D'abord,
regardez la requête :

SELECT OWNERID, 'is in both Orders & Antiques'
FROM ORDERS, ANTIQUES
WHERE OWNERID = BUYERID
UNION
SELECT BUYERID, 'is in Antiques only'
FROM ANTIQUES
WHERE BUYERID NOT IN

     (SELECT OWNERID
     FROM ORDERS);

La première requête effectue une jointure pour lister tous les propriétaires
qui sont dans les deux tables, et met une balise après l'identificateur (ID)
en insérant le texte correspondant à la balise. La clause UNION fusionne cette
liste avec la liste suivante. La seconde liste est générée premièrement en
listant les identificateurs (ID) qui ne sont pas dans la table ORDERS, c'est à
dire en générant une liste des ID exclus de la requête de jointure.. Puis,
chaque ligne de la table ANTIQUES est analysée, et, si l'identifiant de
l'acheteur (BuyerID) n'est pas dans cette liste d'exclusion, il est listé avec
le texte correspondant à sa balise. Il y aurait peut-être une meilleure
manière de créer cette liste, mais c'est difficile de générer des balises
informationnelles.

Ce concept est utile dans des situations où une clé primaire est en relation
avec une clé externe, et où la valeur de la clé externe est NULLE (NULL) pour
quelques clés primaires. Par exemple, dans une table, la clé primaire est
vendeur, et dans une autre table client, avec le vendeur enregistré dans la
même ligne. Cependant, si un vendeur n'a pas de clients, le nom de cette
personne n'apparaîtra pas dans la table des clients. Une jointure externe sera
utilisée pour imprimer une liste de tous les vendeurs, avec leurs clients, que
le vendeur ait un client ou pas--c'est à dire qu'il n'y aura pas de client
imprimé (valeur logique NULL) si le vendeur n'a pas de client, mais existe dans
la table des vendeurs. Autrement, le vendeur sera listé avec chaque client.

ASSEZ DE REQUETES!!! Qu'est-ce que vous dites?...Eh bien, maintenant voyons
quelque chose de complètement différent...

----------------------------------------------------------------------------
SQL incorporé--un vilain exemple (n'écrivez pas un programme comme cela... il
est là UNIQUEMENT à titre d'exemple)

/* -Voici un exemple de programme qui utilise le SQL incorporé (Embedded
    SQL). Le SQL incorporé permet aux programmeurs de se connecter à une
    base de données et d'inclure du code SQL en plein programme, et ainsi,
    leurs programmes peuvent utiliser, manipuler, et traiter les données
    d'une base de données.
   -Cet exemple de Programme C (qui utilise du SQL incorporé) doit imprimer
    un rapport.
   -Les instructions SQL devront être précompilées avant d'effectuer la
    compilation normale.
   -Si vous utilisez un langage différent les parties EXEC SQL seront les
    mêmes (standard), mais le code C qui les entourent devront être
    modifiées, y compris les déclarations de variables hôtes.
   -Le SQL incorporé diffère de système à système, aussi, encore une fois,
    vérifiez la documentation locale, spécialement les déclarations de
    variables et les procédures de connexion pour lesquelles le réseau, le
    SGBD, et le système d'exploitation sont cruciaux. */

/***************************************************/
/* CE PROGRAMME N'EST PAS COMPILABLE OU EXECUTABLE */
/* IL EST UNIQUEMENT DONNE A TITRE D'EXEMPLE       */
/***************************************************/

#include <stdio.h>

/* Section de déclaration des variables hôtes; ce seront les variables
utilisées par votre programme, mais également celles utilisées par SQL
pour y mettre ou y lire des valeurs,. */
EXEC SQL BEGIN DECLARE SECTION;
  int BuyerID;
  char Prenom[100], Nom[100], Item[100];
EXEC SQL END DECLARE SECTION;

/* Cette section,insère les variables SQLCA, de façon à pouvoir tester les erreurs. */
EXEC SQL INCLUDE SQLCA;

main() (

/* Ceci est une possibilité pour se connecter à la base de données */
EXEC SQL CONNECT UserID/Password;

/* Cette partie de code soit vous indique que vous êtes connecté  soit
teste si un code erreur a été généré, signifiant que la connexion était
incorrecte ou impossible. */
  if(sqlca.sqlcode) (
    printf(Printer, "Erreur de connexion au serveur de base de données.\n");
    exit();
  )
  printf("Connecté au serveur de base de données.\n");

/* Ici, on déclare un "Curseur". C'est utilisé lorsqu'une requête retourne
   plus d'une ligne, et qu'on doit effectuer un traitement sur chaque ligne
   obtenue de la requête. Je vais utiliser pour le rapport, chaque ligne obtenue
   par cette requête. Ensuite, on utilisera "FETCH" (va chercher) pour récupérer
   les lignes, une par une, mais pour que la requête soit effectivement exécutée,
   il faut utiliser l'instruction "OPEN". La "Déclaration" (Declare) sert
   uniquement à construire la requête. */
EXEC SQL DECLARE ItemCursor CURSOR FOR
  SELECT ITEM, BUYERID
  FROM ANTIQUES
  ORDER BY ITEM;
EXEC SQL OPEN ItemCursor;

/*
 +-- Insérer ici un test d'erreur similaire au précédent si vous le désirez --+
*/

/* L'instruction FETCH insère les valeurs de la ligne suivante respectivement
dans chacune des variables hôtes. Cependant un "priming fetch" (technique de
programmation) doit être exécuté en premier. Lorsque le curseur n'a plus de
données un code (sqlcode) est généré nous permettant de sortir de la boucle.
Notez que, pour des raisons de simplicité, on abandonne la boucle pour n'importe
quel sqlcode, même s'il correspond à un code erreur. Autrement, il faut
effectuer un test d'erreur spécifique. */
EXEC SQL FETCH ItemCursor INTO :Item, :BuyerID;
  while(!sqlca.sqlcode) (

/* Nous effectuerons également deux traitements pour chaque ligne. Premièrement,
augmenter le prix de 5 (rétribution du marchand) et ensuite, lire le nom de
l'acheteur pour le mettre dans le rapport. Pour faire cela, j'utiliserai les
instructions Update et Select, avant d'imprimer la ligne sur l'écran. La mise à
jour suppose, cependant, qu'un acheteur donné n'a acheté qu'un seul article,
ou, sinon, le prix sera augmenté de trop nombreuses fois. Sinon, il aurait
fallu utiliser une logique "RowID" (consulter la documentation). De plus,
notez la présence du signe : (deux points) qui doit être placé devant les
noms de variables hôtes quand elles sont utilisées dans des instructions
SQL. */

EXEC SQL UPDATE ANTIQUES
  SET PRICE = PRICE + 5
  WHERE ITEM = :Item AND BUYERID = :BuyerID;

EXEC SQL SELECT OWNERFIRSTNAME, OWNERLASTNAME
  INTO :Prenom, :Nom
  FROM ANTIQUEOWNERS
  WHERE BUYERID = :BuyerID;

    printf("%25s %25s %25s", Prenom, Nom, Item);

/* Rapport grossier--uniquement à but d'exemple! Aller chercher la ligne suivante */
EXEC SQL FETCH ItemCursor INTO :Item, :BuyerID;
  )

/* Fermer le curseur, enregistrer les modifications (voir ci-dessous),
et quitter le programme. */
EXEC SQL CLOSE DataCursor;
EXEC SQL COMMIT RELEASE;
  exit();
)

----------------------------------------------------------------------------
Questions courantes sur SQL--Sujets avancés
(Consulter les liens FAQ pour en avoir plusieurs autres)

  1. Pourquoi ne puis-je pas demander uniquement les trois premières lignes
     d'une table? --Parce que, dans une base de données relationnelle, les
     lignes sont insérées sans aucun ordre particulier, c'est à dire que le
     système les insèrent dans un ordre arbitraire; de ce fait, vous ne pouvez
     demander des lignes qu'en utilisant des fonctionnalités SQL valides,
     telles que ORDER BY, etc.
  2. Que sont ces DDL et DML dont j'entends parler ? --DDL (Data
     Definition Language - Langage de Définition de Données) fait référence à
     (en SQL) l'instruction de Création de Table (Create Table)...DML (Data
     Manipulation Language - Langage de Manipulation de Données) fait référence
     aux instructions Select, Update, Insert, et Delete.
  3. Les tables des base de données ne sont elles pas simplement des fichiers?
     --Eh bien, les SGBD stockent les données dans des fichiers déclarés par
     le gestionnaire du système avant que de nouvelles tables ne soient créées
     (sur les grands systèmes), mais le système stocke les données dans un
     format spécial, et peut répartir les données d'une table dans plusieurs
     fichiers. Dans le monde des bases de données, un ensemble de fichiers
     créés pour une base de données est appelé un "espace de tables". En
     général, sur les petits systèmes, tout ce qui concerne une base de données
     (définitions et toutes les tables de données) est stocké dans un seul
     fichier.
  4. (Question en relation avec la précédente) Les bases de données ne sont
     elles pas simplement que des tableurs? --Non, et ceci pour deux raisons.
     Premièrement, les tableurs peuvent avoir des données dans une cellule, mais
     une cellule est plus qu'une intersection ligne-colonne. Selon votre
     tableur, une cellule peut aussi contenir des formules et un formatage,
     ce que les bases de données (actuelles) ne permettent pas. Deuxièmement,
     les cellules dépendent souvent des données présentes dans d'autres
     cellules. Dans les bases de données, les "cellules" sont indépendantes,
     sauf que les colonnes sont en relation logique (heureusement: ensembles,
     une ligne et une colonne décrivent une entité), et, en dehors des
     contraintes de clé primaire et de clé externe, chaque ligne d'une table
     est indépendante des autres.
  5. Comment puis-je importer un fichier texte de données dans une base de
     données? --Eh bien, vous ne pouvez pas le faire directement...il vous faut
     utiliser un programme utilitaire, tel que le SQL*Loader pour Oracle,
     ou écrire un programme pour charger les données dans la base de données.
     Un programme pour réaliser cela lit simplement chaque enregistrement du
     fichier texte, le sépare en colonnes, et effectue une insertion (INSERT)
     dans la base de données.
  6. Qu'est-ce qu'un schéma? --Un schéma est un ensemble logique de tables, tel
     que la base de données ANTIQUES ci-dessus...habituellement, on s'y réfère
     simplement en tant que "base de données", mais une base de données peut
     contenir plus d'un schéma. Par exemple, un schéma en étoile est un ensemble
     de tables où une table centrale, de grande taille, contient toutes les
     informations importantes, et est liée, via des clés externes, à des tables
     de dimension qui contiennent l'information détaillée, et qui peuvent être
     utilisées dans une jointure pour créer des rapports détaillés.
  7. Quels conseils généraux pourriez vous donner pour rendre mes requêtes SQL
     et mes bases de données meilleures et plus rapides (optimisées)?
        o Vous devriez essayer, si vous le pouvez, d'éviter, dans les clauses
          SELECT, des expressions telles que SELECT ColumnA + ColumnB, etc.
          L'optimiseur de requêtes de la base de données, partie du SGBD qui
          détermine la meilleure manière d'extraire les données requises de la
          base de données elle-même, traite les expressions d'une façon telle
          que cela demande en général plus de temps pour extraire les données
          que si les colonnes avaient été sélectionnées normalement, et que
          l'expression elle-même calculée par programme.
        o Minimisez le nombre de colonnes incluses dans une clause Group By.
        o Si vous effectuez une jointure, tâchez d'avoir les colonnes, de cette
          jointure, indexées (dans les deux tables).
        o Si vous avez un doute, créez un index.
        o A moins que vous ne fassiez de multiple comptages ou une requête
          complexe, utilisez COUNT(*) (le nombre de lignes sera généré par la
          requête) plutôt que COUNT(Column_Name).
  8. Qu'est-ce que la Normalisation? --La Normalisation est une technique de
     conception de base de données qui suggère qu'un certain critère doit être
     pris en compte quand on définit l'organisation des tables (prise de
     décision sur le nombre de colonnes de chaque table, et création de la
     structure des clés), où l'idée est d'éliminer la redondance à travers les
     tables des données qui ne sont pas des clés. On parle de la normalisation
     en s'y référant habituellement en termes de "formes", et j'introduirais ici
     uniquement les trois premières, bien qu'il soit tout à fait courant d'en
     utiliser d'autres formes, plus avancées (quatrième, cinquième, Boyce-Codd;
     consultez la documentation).

     La Première Forme Normale consiste à placer les données dans des tables
     séparées où les données dans chaque tables sont de type similaire, et à
     donner à chaque table une clé primaire.

     Mettre les données en Seconde Forme Normale consiste à mettre les données
     dans les tables où elle ne dépendent uniquement que d'une partie de la clé.
     Par exemple, si j'avais laissé les noms des propriétaires d'objets anciens
     dans la table des articles, ce n'aurait pas été une seconde forme normale
     puisque les données auraient été redondantes; le nom aurait dû être
     répété pour chaque article possédé, donc, les noms ont été placés dans
     leur propre table. Les noms en eux-mêmes n'ont rien à voir avec les
     articles, seules les identités des acheteurs et des vendeurs sont
     concernées.

     La Troisième Forme Normale consiste à se débarrasser, dans une table, à
     tout ce qui ne dépend pas uniquement de la clé primaire. On met uniquement
     l'information qui dépend de la clé, et l'on déplace, dans d'autres tables,
     tout ce qui est indépendant de la clé primaire, et l'on crée des clés
     primaires pour les nouvelles tables.

     Il y a une certaine forme de redondance dans chaque forme, et si les
     données sont en 3NF (abrégé pour 3ième forme normale), elles sont déjà en
     1NF et 2NF. En terme d'organisation des données, organisez vos données de
     façon que les colonnes qui ne sont pas des clés primaires dépendent
     seulement de la clé primaire entière. Si vous jetez un oeil sur la base de
     données en exemple, vous verrez que, lorsque vous naviguez à travers la
     base de données, c'est au travers de jointures qui utilisent les colonnes
     de clé commune.

     Deux autre points importants dans la conception de bases de données sont
     l'utilisation de noms significatifs, bien choisis, cohérents et logiques
     pour les tables et les colonnes et l'utilisation de noms significatifs pour
     la base de données elle-même. Sur le dernier point, ma base de données
     pèche, puisque j'utilise des codes numériques comme identificateurs. C'est
     en général bien meilleur d'utiliser, si possible, des clés qui ont, en
     elles-mêmes, un sens; par exemple, une meilleure clé pourrait consister
     des quatre premières lettres du nom et de la première initiale du prénom,
     comme JONEB pour Bill Jones (ou pour éviter les doubles, ajoutez-y des
     nombres à la fin pour différencier deux ou plusieurs personnes ayant le
     même nom, ainsi, on pourrait essayer JONEB1, JONEB2, etc.).
  9. Quelle est la différence entre une requête simple ligne et une requête
     multi-lignes et pourquoi est-ce important de connaître cette
     différence? --Premièrement, pour parler de ce qui est évident, une requête
     simple ligne est une requête qui retourne une ligne unique comme résultat,
     et le résultat d'une requête multi-lignes est constitué de plusieurs
     lignes. Qu'une requête retourne une ligne ou plusieurs dépend complètement
     de la conception (ou schéma) des tables qui constituent la base de données.
     Assurez-vous d'inclure suffisamment de conditions, et structurez vos
     instructions SQL correctement, de façon à obtenir le résultat désiré (soit
     une ligne, soit plusieurs). Par exemple, si vous vouliez être sûr qu'une
     requête sur la table AntiqueOwners ne retourne qu'une ligne, employez une
     condition d'égalité sur la clé primaire, OwnerID.

     Trois raisons, concernant l'importance de ce sujet, viennent immédiatement
     à l'esprit.
     Premièrement, l'obtention de plusieurs lignes alors que vous n'en attendez
     qu'une, ou vice-versa, peut signifier que la requête est erronée, que la
     base de données est incomplète, ou simplement que vous découvrez quelque
     chose de nouveau concernant vos données.
     Deuxièmement, si vous utilisez une instruction de mise à jour (UPDATE) ou
     de suppression (DELETE), il vaudrait mieux vous assurer que l'instruction
     que vous écrivez effectue bien l'opération sur la ligne désirée (ou les
     lignes)...ou sinon, vous pourriez supprimer ou mettre à jour plus de lignes
     que vous ne le désirez.
     Troisièmement, il faut soigneusement penser au nombre de lignes qui seront
     retournées pour toutes les requêtes rédigées  en SQL incorporé. Si vous
     écrivez une requête simple ligne, une seule instruction SQL peut suffire
     pour satisfaire à la logique du programme. D'un autre côté, si votre
     requête retourne de multiples lignes, il vous faudra utiliser
     l'instruction FETCH, et très certainement quelque chose comme une structure
     de boucle sera nécessaire dans votre programme pour traiter chaque ligne
     retournée par la requête.
 10. Que sont les relations? --C'est une autre question de conception...le
     terme "relation" fait habituellement référence aux relations entre clés
     primaires et externes entre les tables. Ce concept est important parce que,
     quand les tables d'une base de données relationnelle sont conçues, ces
     relations doivent être définies parce que cela détermine quelles colonnes
     sont ou ne sont pas des clés primaires ou externes. Vous avez peut-être
     entendu parler des diagrammes Entités-Relations, qui sont une
     représentation graphique des tables dans les schéma de la base de données.
     Voyez l'exemple de diagramme à la fin de cette section ou consultez
     quelques sites indiqués ci-dessous concernant ce sujet, car il y a de
     nombreuses manières de dessiner les diagrammes E-R. Mais d'abord, jetons
     un oeil à chaque type de relation...

     Une relation 1-à-1 (ou 1:1, ou 1-1) signifie que vous avez une colonne clé
     primaire  et que chaque clé primaire est en relation avec une clé externe.
     Par exemple, dans le premier exemple, dans la table des adresses des
     employés TableAdresseEmploye nous avons une colonne numéro d'identification
     de l'employé (EmployeeIDNo). Donc, la table TableAdresseEmploye est en
     relation avec la table EmployeeStatisticsTable (deuxième exemple de table)
     par l'intermédiaire du numéro EmployeeIDNo. Plus précisément, chaque
     employé, de la table TableAdresseEmploye possède des statistiques (une
     ligne de données) dans la table EmployeeStatisticsTable. Même si c'est un
     exemple inventé, c'est une relation "1-1". Inscrivez en caractères gras le
     "has" ("a" ou "possède")...quand on décrit une relation, il est important
     de décrire une relation en utilisant un verbe.

     Les deux autres types de relations peuvent ou pas utiliser une clé primaire
     logique et des contraintes par rapport aux clés externes...cela dépend
     strictement des souhaits du concepteur. La première de ces relations est la
     relation un-à-plusieurs ("1-M").
     Cela signifie que pour chaque valeur d'une colonne dans une table, il y a
     une ou plusieurs valeurs correspondantes dans une autre table. Des
     contraintes de clé peuvent être ajoutées au modèle, ou éventuellement une
     colonne d'identification peut être utilisée pour établir une relation. Un
     exemple serait que pour chaque OwnerID dans la table AntiqueOwners, il y
     ait un ou plusieurs (la valeur zéro est également autorisée) articles
     (Items) achetés dans la table  ANTIQUES (verbe: acheter).

     Finalement, la relation plusieurs-à plusieurs ("M-M") n'utilise
     généralement pas de clés, et habituellement utilise des identificateurs de
     colonnes. L'apparition inhabituelle d'une relation "M-M" signifie qu'une
     colonne, dans une table est en relation avec une autre colonne dans une
     autre table, et que pour chaque valeur de l'une de ces deux colonnes, il y
     a une ou plusieurs valeurs correspondantes dans la colonne correspondante
     de l'autre table (et vice-versa), ou possibilité plus courante, les deux
     tables ont une relation  1-M avec l'autre (deux relations, une 1-M dans
     chaque direction). Un [mauvais] exemple de la situation la plus courante
     consisterait, si vous avez une bases de données de fonctions, à avoir une
     table possédant une ligne pour chaque employé et sa fonction, et d'avoir
     une autre table contenant une ligne pour chaque fonction avec un des
     employés l'occupant. Dans ce cas, vous auriez plusieurs lignes pour chaque
     employé dans la première table, une pour chaque fonction, et plusieurs
     lignes pour chaque fonction dans le seconde table, une pour chaque employé
     ayant cette fonction.
     Ces tables sont en relation M-M: chaque employé, dans la première table a
     plusieurs fonctions dans la seconde table, et chaque fonction, dans la
     seconde table, a plusieurs attributaires dans la première table. Ceci est
     la partie émergée de l'iceberg concernant ce sujet...consultez les liens
     ci-dessous pour avoir de plus amples informations et regardez le diagramme
     ci-dessous donnant un exemple simplifié de diagramme E-R.
     [Exemple Simplifié de Diagramme Entités-Relations]

 11. Quelles sont quelques unes des fonctionnalités importantes, non standard,
     de SQL (Question extrêmement courante)? --Eh bien, nous allons voir çà dans
     la section suivante...

----------------------------------------------------------------------------
SQL Non-standard..."A vérifier pour votre site"

   * INTERSECT et MINUS sont comme des instructions UNION , sauf que INTERSECT
     produits des lignes qui apparaissent dans les deux requêtes, et que MINUS
     produit des lignes provenant de la première requête mais pas de la
     seconde.
   * Fonctionnalités de la Génération de Rapport: la clause COMPUTE est placée
     à la fin d'une requête pour placer le résultat d'une fonction agrégée à
     la fin d'une liste, comme COMPUTE SUM (PRICE); Une autre solution est
     d'utiliser une logique d'interruption: définir une interruption pour
     diviser les résultats de la requête en groupes basés sur une colonne,
     comme BREAK ON BUYERID. Alors, pour sortir un résultat après la liste d'un
     groupe, utilisez COMPUTE SUM OF PRICE ON BUYERID. Si, par exemple, vous
     avez utilisé ces trois clauses ("BREAK" en premier, "COMPUTE on break" en
     second, "COMPUTE overall sum" en troisième), vous obtiendrez un rapport qui
     regroupera les articles par acheteurs, listera la somme de Prix pour chaque
     groupe d'articles d'un acheteur, puis, après que tous les groupes aient été
     listés, listera la somme de tous les Prix, le tout, avec des en-têtes et
     des lignes générés par SQL.
   * En plus des fonctions agrégées indiquées ci-dessus, quelques SGBD ont des
     fonctions supplémentaires qui peuvent être utilisées dans des listes de
     sélection (SELECT), sauf que ces fonctions (quelques fonctions caractères
     autorisent des résultats de plusieurs lignes) doivent être utilisées avec
     une valeur individuelle (pas de groupes), pour des requêtes simple ligne.
     De plus, les fonctions ne doivent être utilisées qu' avec les types de
     données appropriés. Voici quelques Fonctions Mathématiques:

      ABS(X)       Valeur A-convertit les nombres négatifs en nombres positifs
                   et laisse les positifs inchangés
      CEIL(X)      X est une valeur décimale qui sera arrondie à la valeur
                   supérieure.
      FLOOR(X)     X est une valeur décimale qui sera arrondie à la valeur
                   inférieure.
      GREATEST(X,Y)Retourne la plus grande des deux valeurs.
      LEAST(X,Y)   Retourne la plus petite des deux valeur.
      MOD(X,Y)     Retourne le reste de X / Y.
      POWER(X,Y)   Retourne X à la puissance Y.

      ROUND(X,Y)   Arrondit X à Y positions décimales. i Y n'est pas donné, X
                   est arrondi à la valeur de l'entier le plus proche.
      SIGN(X)      Retourne le signe - si X < 0, sinon retourne un signe plus.
      SQRT(X)      Retourne la racine carrée de  X.

                               Fonctions Caractères

      LEFT(<string>,X)
                           Retourne les X caractères les plus à gauche de la
                           chaîne de caractères.

      RIGHT(<string>,X)
                           Retourne les X caractères les plus à droite de la
                           chaîne de caractères.
      UPPER(<string>)
                           Convertit tous les caractères de la chaîne en
                           majuscules.
      LOWER(<string>)
                           Convertit tous les caractères de la chaîne en
                           minuscules.
      INITCAP(<string>)
                           Convertit les caractères initiaux de la chaîne en
                           Capitales.
      LENGTH(<string>)
                           Retourne le nombre de caractères de la chaîne.

      <string>||<string>
                           Combine les deux chaînes en une seule chaîne,
                           concaténée, où la première chaîne est immédiatement
                           suivie par la seconde.

      LPAD(<string>,X,'*')
                           Insère des caractères * (ou n'importe quel autre, mis
                           entre guillemets) à gauche de la chaîne de
                           caractères pour lui donner une longueur de X
                           caractères.

      RPAD(<string>,X,'*')
                           Insère des caractères * (ou n'importe quel autre, mis
                           entre guillemets) à droite de la chaîne de
                           caractères pour lui donner une longueur de X
                           caractères.

      SUBSTR(<string>,X,Y)
                           Extrait Y lettres de la chaîne à partir de la
                           position X.

      NVL(<column>,<value>)
                           La fonction NVL va substituer la valeur <value>
                           pour chaque valeur nulle dans la colonne <column>. Si
                           la valeur courante dans la colonne <column> n'est pas
                           nulle (NULL), NVL est sans effet.

----------------------------------------------------------------------------
Résumé de la Syntaxe--Pour Utilisateurs Avancés Seulement

Voici la forme générale des instructions dont il a été question dans ce
didacticiel, avec, en plus, quelques autres, (des explications sont données).
SOUVENEZ-VOUS que toutes ces instructions peuvent ne pas être disponibles sur
votre système, aussi vérifiez leur disponibilité dans la documentation:

ALTER TABLE <TABLE NAME> ADD|DROP|MODIFY (COLUMN SPECIFICATION[S]...voir
Create Table); --vous permet d'ajouter ou de supprimer une ou plusieurs colonnes
d'une table, ou de changer les spécifications(données, types, etc.) d'une colonne
existante;
cette instruction est également utilisée pour changer les spécifications
physiques d'une table
(comment la table est stockée, etc.), mais ces définitions sont spécifiques au
SGBD, aussi, lire la documentation. De même, ces spécifications physiques sont
utilisées avec les instructions de création de table, lorsqu'une table est créée
pour la première fois. De plus, seulement une seule option peut être exécutée
par instruction de modification: (Alter Table)--soit add (ajout), drop
(suppression), OU modify (modification) dans une simple instruction.

COMMIT; --rend les modifications effectuées sur une bases de données permanentes
(depuis le dernier COMMIT; connu sous le nom de transaction)

CREATE [UNIQUE] INDEX <INDEX NAME>
ON <TABLE NAME> (<COLUMN LIST>); --UNIQUE est optionnel; entre parenthèses.

CREATE TABLE <TABLE NAME>
(<COLUMN NAME> <DATA TYPE> [(<SIZE>)] <COLUMN CONSTRAINT>,
...autres colonnes); (valide également avec ALTER TABLE)
--où SIZE est uniquement utilisé avec certains types de données (voir
ci-dessus), et les contraintes incluent les possibilités suivantes (imposé
automatiquement par le SGBD;
(un non respect entraîne la génération d'une erreur) :

  1. NULL ou NOT NULL (voir ci-dessus)
  2. UNIQUE impose que deux lignes ne peuvent avoir la même valeur pour cette
colonne
  3. PRIMARY KEY indique à la base de données que cette colonne est la colonne
clé primaire (utilisé uniquement si la clé est une colonne clé, autrement une
instruction
     PRIMARY KEY (column, column, ...) apparaît après la dernière définition de
colonne.
  4. CHECK permet de tester une condition quand on insère ou on met à jour une
donnée dans cette colonne; par exemple, CHECK (PRICE > 0) amène le système à
tester si la colonne Prix est supérieure ou égale à zéro avant d'accepter la
valeur...quelquefois implanté comme instruction CONSTRAINT.
  5. DEFAULT insère une valeur par défaut dans la base de données si l'on veut
insérer une ligne qui ne contienne pas de valeur pour cette colonne; par
exemple,
     BENEFITS INTEGER DEFAULT = 10000
  6. FOREIGN KEY fonctionne comme la Clé Primaire, mais est suivi par:
     REFERENCES <TABLE NAME> (<COLUMN NAME>), qui fait référence à la clé primaire
     de référence.

CREATE VIEW <TABLE NAME> AS <QUERY>;

DELETE FROM <TABLE NAME> WHERE <CONDITION>;

INSERT INTO <TABLE NAME> [(<COLUMN LIST>)]
VALUES (<VALUE LIST>);

ROLLBACK; --Annule toutes les modifications effectuées dans la base de données,
celles qui ont été faites depuis la dernière commande COMMIT...Attention!
Quelques logiciels travaillant en transactions, donc, la commande ROLLBACK peut
ne pas fonctionner.

SELECT [DISTINCT|ALL] <LIST OF COLUMNS, FUNCTIONS, CONSTANTS, ETC.>
FROM <LIST OF TABLES OR VIEWS>
[WHERE <CONDITION(S)>]
[GROUP BY <GROUPING COLUMN(S)>]
[HAVING <CONDITION>]
[ORDER BY <ORDERING COLUMN(S)> [ASC|DESC]]; --où ASC|DESC permet le classement en
ordre ascendant (ASCending) ou descendant (DESCending)

UPDATE <TABLE NAME>
SET <COLUMN NAME> = <VALUE>
[WHERE <CONDITION>]; --si la clause WHERE n'est pas donnée, toutes les lignes
seront mises à jour selon l'instruction SET

----------------------------------------------------------------------------
Liens Importants

Liens Informatique & SQL/DB : Netscape -- Oracle -- Sybase -- Informix
--Microsoft
Page de Référence -- Ask the SQL Pro -- SQL Pro's Relational DB
Sites Utiles
Programmer's Source -- DBMS Sites -- inquiry.com -- DB Ingredients
Web Authoring -- Computing Dictionary -- DBMS Lab/Links -- SQL FAQ -- SQL
Databases
RIT Database Design Page -- Database Jump Site -- Didacticiels de programmation sur le Web
Ressources pour le Développement -- Query List -- IMAGE SQL

Divers: CNN -- USA Today -- Pathfinder -- ZDNet -- Metroscope -- CNet

Liste de ressources sur Internet -- Netcast Weather -- TechWeb -- LookSmart

Moteurs de Recherche: Yahoo -- Alta Vista -- Excite -- WebCrawler -- Lycos --
Infoseek -- search.com

L'auteur n'est pas reponsable de ces sites.
----------------------------------------------------------------------------
Avertissement

J'espère que vous aurez appris quelque chose de ce premier regard sur un langage
très important qui est en train de devenir plus répandu dans le mode de
l'informatique client-serveur. J'ai rédigé cette page web pour apporter quelque
chose d'utile au  web et à la communauté des utilisateurs du web. En réalité,
j'ai appris que ce document est utilisé dans plusieurs collèges pour des cours
sur les bases de données et par des chercheurs. En outre, lisez cette page dans
le nouveau livre, édité par Waite Publishing, sur Borland C++ Builder, qui sera
publié cet été et dans une version à venir chez Sams Publishing. De plus, je
voudrais remercier tous les gens, sur les cinq continents, qui m'ont contactés
à propos de cette page.

J'espère aussi continuer à ajouter plus d'éléments à ce didacticiel, tels que
des articles sur la conception d'une base de données et les extensions SQL non
standard, même si je souhaite me tenir à l'écart de particularités propres à
un Système de Gestion de Base de Donnée. Bonne chance pour vos développements
en SQL et autres aventures informatiques.

Jim Hoffman
----------------------------------------------------------------------------
Commentaires ou Suggestions? Envoyez-moi un courrier électronique à jhoffman@one.net.

Ou vous pouvez désirer jeter un oeil aux pages Web de  Jim Hoffman's Web Pages
pour plus d'informations me concernant.

Copyright 1996-1997, James Hoffman. Ce document peut être utilisé gratuitement
par n'importe quel utilisateur d'Internet, mais ne peut pas être inclus dans
un autre document, publié sous une autre forme, ou produit en masse de quelque
façon que ce soit.

Netscape Navigator donne le meilleur affichage de cette page; celui-ci n'est pas
très bon si l'on utilise Microsoft Internet Explorer.

Dernière mise à jour : 8-25-1997; ajout de quelques éléments.


Page suivante Page précédente Table des matières