S
tructuredQ
ueryL
anguagePar Th. COSNUAU
Un modèle de données est un ensemble de concepts et de règles de composition de ces concepts permettant de décrire des données.
Il existe principalement trois types de modèles :
Le modèle relationnel a été initié par CODD à IBM en 1970 mais fut surtout utilisé à partir des années 1980.
Le langage de manipulation de données relationnelles se compose d'un ensemble de commandes permettant d'interroger et de modifier une base de données.
Ce " langage de requête structuré " (SQL = Structured Query Language) est une évolution (1981) du langage SEQUEL d'IBM.
Il permet notamment d'exprimer de façon simple, des sélections, des projections et des jointures.
On distingue trois sous ensembles :
Le SQL est un langage déclaratif dont la syntaxe est très simple (comme beaucoup de langages de ce type) ce qui permet de se concentrer sur le problème à résoudre.
Tables utilisées dans les exemples
Les exemples cités dans ce document ont tous été testés sous ORACLE , un des systèmes de gestion de bases de données relationnels les plus répandus sur le marché.
Ces exemples sont bâtis sur une base de données composée des deux relations suivantes :
NOM |
NUM |
FONCTION |
N_SUP |
EMBAUCHE |
SALAIRE |
COMM |
N_DEPT |
MARTIN |
16712 |
directeur |
25717 |
23-MAY-90 |
40000 |
30 |
|
DUPONT |
17574 |
administratif |
16712 |
03-MAY-95 |
9000 |
30 |
|
DUPOND |
26691 |
commercial |
27047 |
04-APR-88 |
25000 |
2500 |
20 |
LAMBERT |
25012 |
administratif |
27047 |
14-APR-91 |
12000 |
20 |
|
JOUBERT |
25717 |
président |
10-OCT-82 |
50000 |
30 |
||
LEBRETON |
16034 |
commercial |
27047 |
01-JUN-91 |
15000 |
0 |
20 |
MARTIN |
17147 |
commercial |
27047 |
10-DEC-93 |
20000 |
500 |
20 |
PAQUEL |
27546 |
commercial |
27047 |
03-SEP-83 |
22000 |
2000 |
20 |
LEFEBVRE |
25935 |
commercial |
27047 |
11-JAN-84 |
23500 |
1500 |
20 |
GARDARIN |
15155 |
ingénieur |
24533 |
22-MAR-85 |
24000 |
10 |
|
SIMON |
26834 |
ingénieur |
24533 |
04-OCT-88 |
20000 |
10 |
|
DELOBEL |
16278 |
ingénieur |
24533 |
16-NOV-94 |
21000 |
10 |
|
ADIBA |
25067 |
ingénieur |
24533 |
05-PCT-87 |
30000 |
10 |
|
CODD |
24533 |
directeur |
25717 |
12-SEP-75 |
55000 |
10 |
|
LAMERE |
27047 |
directeur |
25717 |
07-SEP-89 |
45000 |
20 |
|
BALIN |
17232 |
administratif |
24533 |
03-OCT-87 |
13500 |
10 |
|
BARA |
24831 |
administratif |
16712 |
10-SEP-88 |
15000 |
30 |
N_DEPT |
NOM |
LIEU |
10 |
recherche |
Rennes |
20 |
vente |
Metz |
30 |
direction |
Gif |
40 |
fabrication |
Toulon |
La commande SELECT constitue, à elle seule, le langage permettant d'interroger une base de données. Elle permet :
Une interrogation, on parle plutôt de requête, est une combinaison d'opérations portant sur des tables (relations) et dont le résultat est lui-même une table dont l'existence est éphémère (le temps de la requête).
Note :
On peut introduire un commentaire à l'intérieur d'une commande SQL en l'encadrant par /* */ .
La commande
SELECT la plus simple a la syntaxe suivante :SELECT * FROM nom_table ;
dans laquelle :
Par défaut toutes les lignes sont sélectionnées. On peut limiter la sélection à certaines colonnes, en indiquant une liste de noms de colonnes à la place de l'astérisque.
SELECT nom_col1, nom_col2, ... FROM nom_table ;
Exemple :
Donner le nom et la fonction de chaque employé.SELECT nom, fonctionFROM emp;
La clause DISTINCT ajoutée derrière la commande SELECT permet d'éliminer les duplications.
Exemple : Quelles sont toutes les fonctions différentes.
SELECT DISTINCT fonctionFROM emp;
La clause
WHERE permet de spécifier quelles sont les lignes à sélectionner. Elle est suivie d'un prédicat qui sera évalué pour chaque ligne de la table. Les lignes pour lesquelles le prédicat est vrai seront sélectionnées.La syntaxe est la suivante :
SELECT * FROM nom_table WHERE predicat ;
Un prédicat n'est ni plus ni moins que la façon dont on exprime une propriété. Les prédicats, qu'ils soient simples ou composés, sont constitués à partir d'expressions que l'on compare entre elles.
Une expression simple peut être :
Les expressions peuvent être de trois types : numérique, chaîne de caractères ou date. A chacun de ces types correspond un format de constante :
On peut, en SQL, exprimer des expressions plus complexes en utilisant des opérateurs et des fonctions étudiés dans le chapitre
Expressions et fonctions.
Un prédicat simple est le résultat de la comparaison de deux expressions au moyen d'un opérateur de comparaison qui peut être :
Les trois types d'expressions peuvent être comparés au moyen de ces opérateurs :
Il faut ajouter à ces opérateurs arithmétiques classiques les opérateurs suivants :
Exemple : Quels sont les employés dont la commission est supérieure au salaire ?
SELECT nom, salaire, commFROM empWHERE comm > salaire;
Exemple : Quels sont les employés gagnant entre 20000 et 25000?
SELECT nom, salaireFROM empWHERE salaire BETWEEN 20000 AND 25000;
Exemple : Quels sont les employés commerciaux ou ingénieurs?
SELECT num, nom, fonction, salaireFROM empWHERE fonction IN ('commercial','ingenieur');
Exemple : Quels sont les employés dont le nom commence par M?
SELECT nomFROM empWHERE nom LIKE 'M%';
Les opérateurs logiques
AND (et) et OR (ou inclusif) peuvent être utilisés pour combiner entre eux plusieurs prédicats. L'opérateur NOT placé devant un prédicat en inverse le sens.L'opérateur
AND est prioritaire par rapport à l'opérateur OR. Des parenthèses peuvent être utilisées pour imposer une priorité dans l'évaluation du prédicat, ou simplement pour rendre plus claire l'expression logique.Exemple : Quels sont les employés du département 30 ayant un salaire supérieur à 25000?
SELECT nomFROM empWHERE n_dept = 30AND salaire > 25000;
Exemple : Quels sont les employés directeurs, ou commerciaux et travaillant dans le département 10?
SELECT nom, fonction, salaire, n_deptFROM empWHERE fonction = 'directeur'
OR (fonction = 'commercial' AND n_dept = 10);
La requête précédente donnerait le même résultat sans les parenthèses, résultat différent de celui du
SELECT suivant.
Exemple : Quels sont les employés directeurs ou commerciaux, et travaillant dans le département 10?
SELECT num, nom, fonction, n_deptFROM empWHERE (fonction='directeur' OR fonction = 'commercial') AND n_dept = 10;
Pour SQL, une valeur
NULL est une valeur non définie. Il est possible d'ajouter une ligne à une table sans spécifier de valeur pour les colonnes non obligatoires : ces colonnes absentes auront la valeur NULL.Par exemple les employés dont la rémunération ne prend pas en compte de commission auront une valeur
NULL, c'est-à-dire indéfinie, comme commission.L'opérateur
IS NULL permet de tester la valeur NULL : le prédicat expr IS NULL est vrai si l'expression a la valeur NULL (c'est-à-dire si elle est indéfinie).Exemple : Quels sont les employés dont la commission a la valeur
NULL?SELECT nomFROM empWHERE comm IS NULL;
L'opérateur
IS NOT NULL permet de construire un prédicat vrai si la valeur n'est pas NULL (et donc le prédicat expr IS NOT NULL est vrai si expr est définie)Remarques
Les colonnes constituant le résultat d'un
SELECT peuvent être renommées dans le SELECT, ceci est utile en particulier lorsque la colonne résultat est une expression. Pour cela, il suffit de faire suivre l'expression définissant la colonne d'un nom, selon les règles suivantes :Ce nom est celui sous lequel la colonne sera connue des interfaces externes. Sous
SQLPLUS, par exemple, il constituera le titre par défaut de la colonne, et servira de référence pour définir un format pour la colonne.Exemple : Salaire de chaque employé.
SELECT nom, salaire "SALAIRE MENSUEL"FROM emp;
Remarque : Attention, ce nom n'est pas connu à l'intérieur du
SELECT.
Les lignes constituant le résultat d'un
ORDER BY {nom_col1 | num_col1 [DESC] [, nom_col2 | num_col2 [DESC],...]}
Le classement se fait d'abord selon la première colonne spécifiée dans l'
ORDER BY puis les lignes ayant la même valeur dans la première colonne sont classées selon la deuxième colonne de l'ORDER BY, etc... Pour chaque colonne, le classement peut être ascendant (par défaut) ou descendant (DESC).Exemple : Donner tous les employés classés par fonction, et pour chaque fonction classés par salaire décroissant
SELECT nom, fonction, salaireFROM empORDER BY fonction, salaire DESC;
Remarque : Dans un classement les valeurs
NULL sont toujours en tête quel que soit l'ordre du classement (ascendant ou descendant).
SELECT [DISTINCT | ALL] { * | { [schema.]{table | view | snapshot}.* | expr [c_alias] [, { [schema.]{table | view | snapshot}.* | expr [c_alias] } ] ... } FROM [schema.]{table | view | snapshot} [t_alias] [, [schema.]{table | view | snapshot} [t_alias] ] ... [WHERE condition ] [ [START WITH condition] CONNECT BY condition] [GROUP BY expr [, expr] ... [HAVING condition] ] [{UNION | UNION ALL | INTERSECT | MINUS} SELECT command ] [ORDER BY {expr|position} [ASC | DESC] [, {expr | position} [ASC | DESC]] ...] [FOR UPDATE [OF [[schema.]{table | view}.]column [, [[schema.]{table | view}.]column] ...] [NOWAIT] ]
Pour pouvoir sélectionner des lignes d'un objet(table, vue, cliché) il faut soit être propriétaire de cet objet, soit avoir le privilège SELECT sur cet objet.
Le privilège SELECT ANY TABLE permet de sélectionner des lignes de n'importe quel objet appartenant à n'importe quel utilisateur.
La jointure est une opération permettant de combiner des informations venant de plusieurs tables. Les exemples suivants se limiteront à deux tables, mais on peut joindre jusqu'à 256 tables. Une jointure se formule simplement en spécifiant plusieurs tables derrière le
FROM de la façon suivante :SELECT ... FROM nom_table1, nom_table2... WHERE predicat;
Si on ne précise pas de condition de sélection, le résultat obtenu sera le produit cartésien des tables présentes derrière le
FROM (résultat non souhaité en général).Il n'existe pas d'associations implicites ou explicites entre les tables dans SQL. Les associations entre les tables sont définies dynamiquement lors des interrogations, ce qui contribue à la grande souplesse du langage sql et rend possible toute association même si elle n'a pas été prévue lors de la définition et du chargement de la base.
Equi-jointure
Le rapprochement de chaque ligne de la table
emp avec la ligne de la table dept ayant même numéro de département permet d'obtenir la liste des employés avec la localité dans laquelle ils travaillent. Ce rapprochement entre deux colonnes appartenant à deux tables différentes mais ayant le même sens (ici le numéro de département) et venant vraisemblablement d'une relation 1-n lors de la conception (ici 1 entité département pour n entités employés) est assez naturel. C'est pourquoi ce type de jointure porte le nom de jointure naturelle ou d'équi-jointure.Exemple : Donner pour chaque employé son nom et son lieu de travail.
SELECT emp.nom, lieuFROM emp, deptWHERE emp.n_dept = dept.n_dept;
Le fait que la colonne contenant le numéro de département ait le même nom dans les deux tables a rendu nécessaire le préfixage par le nom de table dans le critère de jointure (clause
WHERE). Le nom de colonne nom a lui aussi besoin d'être préfixé car il appartient aux deux tables (nom de la personne dans l'une et nom du département dans l'autre). Par contre le nom de colonne lieu n'a pas besoin d'être préfixé car il n'y a pas d'ambiguïté sur la table à laquelle cette colonne appartient.
Il peut être utile de rassembler des informations venant d'une ligne d'une table avec des informations venant d'une autre ligne de la même table.
Exemple : Donner pour chaque employé le nom de son supérieur hiérarchique.
SELECT emp.nom, mgr.nomFROM emp, emp mgrWHERE emp.n_sup= mgr.num;
Remarque : Dans ce cas, il faut impérativement renommer au moins l'une des deux occurences de la table (ici
emp) en lui donnant un synonyme, afin de pouvoir préfixer sans ambiguité chaque nom de colonne.Le critère d'égalité est le critère de jointure le plus naturel. Mais on peut utiliser d'autres types de comparaisons comme critères de jointures.
Exemple : Quels sont les employés gagnant plus que
SIMON?SELECT emp.nom, emp.salaire, emp.fonctionFROM emp, emp jWHERE emp.salaire > j.salaireAND J.nom = 'SIMON';
Lorsqu'une ligne d'une table figurant dans une jointure n'a pas de correspondant dans les autres tables, elle ne satisfait pas au critère d'équi-jointure et donc ne figure pas dans le résultat de la jointure.
Une option permet de faire figurer dans le résultat les lignes satisfaisant la condition d'équi-jointure plus celles n'ayant pas de correspondant. Cette option s'obtient en accolant (+) au nom de colonne de la table dans laquelle manquent des éléments, dans la condition d'équi-jointure.
Exemple : Le département 40 ne figurait pas dans le résultat du
SELECT précédent. Par contre, il figurera dans le résultat du SELECT suivant.SELECT emp.nom, lieuFROM emp, deptWHERE emp.n_dept(+) = dept.n_dept;
Le (+) peut s'interpréter comme l'ajout d'une ligne fictive dont toutes les colonnes ont la valeur
NULL, et qui réalise la correspondance avec les lignes de l'autre table qui n'ont pas de correspondant réel. Dans l'exemple ci-dessus, la valeur de nom associée au département 40 est la valeur NULL.
Exemple : Retrouver les départements n'ayant aucun employé.
SELECT dept.n_dept, emp.nomFROM emp,deptWHERE dept.n_dept = emp.n_dept (+)AND emp.nom IS NULL;
Les opérateurs ensemblistes permettent de "joindre" des tables verticalement c'est-à-dire de combiner dans un résultat unique des lignes provenant de deux interrogations. Les lignes peuvent venir de tables différentes mais après projection on doit obtenir des tables ayant même schéma de relation.
Les opérateurs ensemblistes sont les suivants :
La syntaxe d'utilisation est la même pour ces trois opérateurs :
SELECT ... {UNION | INTERSECT | MINUS } SELECT ...
Dans une requête utilisant des opérateurs ensemblistes :
On peut combiner le résultat de plus de deux
SELECT au moyen des opérateurs UNION, INTERSECT, MINUS.SELECT ... UNION SELECT ... MINUS SELECT ...
Dans ce cas l'expression est évaluée de gauche à droite, mais on peut modifier l'ordre d'évaluation en utilisant des parenthèses.
SELECT ... UNION (SELECT ... MINUS SELECT ...)
Les sous-interrogations (Imbrications & Corrélations)
Une caractéristique puissante de SQL est la possibilité qu'un critère de recherche employé dans une clause
WHERE (expression à droite d'un opérateur de comparaison) soit lui-même le résultat d'un SELECT ; c'est ce qu'on appelle une sous-interrogation.Sous-interrogation ramenant une seule valeur
Exemple :
Quels sont les employés ayant la même fonction que CODD ?SELECT nomFROM empWHERE fonction = (SELECT fonction FROM emp WHERE nom ='CODD');
Remarques
Une sous-interrogation peut ramener plusieurs lignes à condition que l'opérateur de comparaison admette à sa droite un ensemble de valeurs. Les opérateurs permettant de comparer une valeur à un ensemble de valeurs sont :
Exemple : Quels sont les employés gagnant plus que tous les employés du département 30.
SELECT nom, salaire FROM empWHERE salaire > ALL (SELECT salaire FROM emp WHERE n_dept = 20);
Il est possible de comparer le résultat d'un
SELECT ramenant plusieurs colonnes à une liste de colonnes. La liste de colonnes figurera entre parenthèses à gauche de l'opérateur de comparaison.Exemple : Quels sont les employés ayant même fonction et même supérieur que
CODD?SELECT nom, fonction, n_supFROM empWHERE (fonction, n_sup) = (SELECT fonction, n_sup FROM emp WHERE nom = 'CODD');
Dans les exemples précédents, la sous-interrogation était évaluée d'abord, puis le résultat pouvait être utilisé pour exécuter l'interrogation principale. SQL sait également traiter une sous-interrogation faisant référence à une colonne de la table de l'interrogation principale. Le traitement dans ce cas est plus complexe car il faut évaluer la sous-interrogation pour chaque ligne de l'interrogation principale.
Exemple : Quels sont les employés ne travaillant pas dans le même département que leur supérieur hiérarchique.
SELECT nomFROM emp eWHERE n_dept != (SELECT n_dept FROM emp WHERE e.n_sup = num)AND n_sup IS NOT NULL;
Il a fallu ici renommer la table
emp de l'interrogation principale pour pouvoir la référencer dans la sous-interrogation.
L'opérateur
EXISTS permet de construire un prédicat vrai si la sous-interrogation qui suit ramène au moins une ligne.Exemple : Quels sont les employés travaillant dans un département qui a procédé à des embauches depuis le début de l'année 94.
SELECT *FROM emp eWHERE EXISTS (SELECT * FROM emp WHERE embauche >= '01-jan-94' AND n_dept = e.n_dept);
Remarque : On peut inverser le sens de l'opérateur
EXISTS en le faisant précéder de NOT.Sous-interrogations multiples
Un
SELECT peut comporter plusieurs sous-interrogations, soit imbriquées, soit au même niveau dans différents prédicats combinés par des AND ou des OR.Exemple : Liste des employés du département 10 ayant même fonction que quelqu'un du département de
DUPONT.SELECT nom, fonctionFROM empWHERE n_dept = 10AND fonction IN (SELECT fonction FROM emp WHERE n_dept = (SELECT n_dept FROM emp WHERE nom = 'DUPONT'));
Expressions et Fonctions simples
Une expression est un ensemble de variables (contenu d'une colonne), de constantes et de fonctions combinées au moyen d'opérateurs. Les fonctions prennent une valeur dépendant de leurs arguments qui peuvent être eux-mêmes des expressions.
Les expressions peuvent figurer :
Il existe trois types d'expressions correspondant chacun à un type de données de SQL : arithmétique, chaîne de caractère, date. A chaque type correspondent des opérateurs et des fonctions spécifiques.
SQL autorise les mélanges de types dans les expressions et effectuera les conversions nécessaires : dans une expression mélangeant dates et chaînes de caractères, les chaînes de caractères seront converties en dates, dans une expression mélangeant nombres et chaînes de caractères, les chaînes de caractères seront converties en nombre.
Expressions et fonctions arithmétiquesUne expression arithmétique peut contenir :
combinés au moyen des opérateurs arithmétiques.
Les opérateurs arithmétiques présents dans sql sont les suivants :
Remarque : la division par 0 provoque une fin avec code d'erreur.
Une expression arithmétique peut comporter plusieurs opérateurs. Dans ce cas, le résultat de l'expression peut varier selon l'ordre dans lequel sont effectuées les opérations. Les opérateurs de multiplication et de division sont prioritaires par rapport aux opérateurs d'addition et de soustraction. Des parenthèses peuvent être utilisées pour forcer l'évaluation de l'expression dans un ordre différent de celui découlant de la priorité des opérateurs.
Exemple : Donner pour chaque commercial son revenu (salaire + commission).
SELECT nom, salaire+commFROM empWHERE fonction = 'commercial';
Exemple : Donner la liste des commerciaux classée par commission sur salaire décroissant.
SELECT nom, comm/salaire, comm, salaireFROM empWHERE fonction = 'commercial'ORDER BY comm/salaire DESC;
Exemple : Donner la liste des employés dont la commission est inférieure à 5% du salaire.
SELECT nom, salaire, commFROM empWHERE comm <= salaire *.05;
Dans ce paragraphe, ont été regroupées les fonctions ayant un ou plusieurs nombres comme arguments, et renvoyant une valeur numérique. [
ROUND(n ,m )]Exemple : Donner pour chaque employé son salaire journalier.
SELECT nom, ROUND(salaire/22,2)FROM emp;
Il existe un seul opérateur sur les chaînes de caractères : la concaténation. Cet opérateur se note au moyen de deux caractères |(barre verticale) accolés. Le résultat d'une concaténation est une chaîne de caractères obtenue en écrivant d'abord la chaîne à gauche de || puis celle à droite de ||.
SELECT nom || '/' || fonctionFROM emp;
Le paragraphe suivant contient les fonctions travaillant sur les chaînes de caractères et renvoyant des chaînes de caractères.
Le paragraphe suivant contient les fonctions travaillant sur les chaînes de caractères et renvoyant des entiers.
Au moyen des opérateurs arithmétiques + et - il est possible de construire les expressions suivantes :
Exemple : Donner la date du lundi suivant l'embauche de chaque employé.
SELECT NEXT_DAY (embauche,'MONDAY')FROM emp;
Exemple : Donner la date d'embauche de chaque employé arrondie à l'année
SELECT ROUND (embauche,'Y')FROM emp;
Exemple : Donner pour chaque employé le nombre de jours depuis son embauche.
SELECT ROUND (SYSDATE-embauche)FROM emp;
Les formats suivants permettent d'obtenir des dates en lettres ( en anglais) :
Les suffixes suivants modifient la présentation du nombre auquel ils sont accolés :
Tout caractère spécial inséré dans le format sera reproduit tel quel dans la chaîne de caractères résultat.
Remarque : On peut également insérer dans le format une chaîne de caractères quelconque, à condition de la placer entre guillemets"".
Exemple :
SELECT TO_CHAR (embauche,'DD/MM/YY HH24:MI:SS')FROM emp;
Exemple : Donner la liste de tous les employés dont le nom ressemble à
DUPONT.SELECT nomFROM empWHERE SOUNDEX(nom) = SOUNDEX('DUPONT');
Exemple : Donner la liste de tous les noms des employés en ayant supprimé tous les 'L' et les 'E' en tête des noms.
SELECT LTRIM(nom,'LE')FROM emp;
Exemple : Donner la liste de tous les noms des employés en ayant remplacé les A et les M par des * dans les noms.
SELECT TRANSLATE (nom,'AM','**')FROM emp;
Exemple : Afficher tous les salaires avec un $ en tête et au moins trois chiffres ( dont deux décimales).
SELECT TO_CHAR (salaire,'<MATH>99900.00')FROM emp;
Exemple :
Donner pour chaque employé ses revenus (salaire + commission).SELECT nom, salaire, comm, salaire+NVL(comm,0)FROM emp;
Exemple : Donner la liste des employés avec pour chacun d'eux sa catégorie (président = 1, directeur = 2, autre = 3)
SELECT nom, DECODE(fonction,'president',1,'directeur',2,3)FROM emp;
Exemple : Donner la liste des employés en les identifiant par leur fonction dans le département 10 et par leur nom dans les autres départements.
SELECT DECODE (n_dept,10,fonction,nom)FROM emp;
Dans les exemples précédents, chaque ligne résultat d'un
SELECT était le résultat de calculs sur les valeurs d'une seule ligne de la table consultée. Il existe un autre type de SELECT qui permet d'effectuer des calculs sur l'ensemble des valeurs d'une colonne. Ces calculs sur l'ensemble des valeurs d'une colonne se font au moyen de l'une des fonctions suivantes :Exemple : Donner le total des salaires du département 10.
SELECT SUM(salaire)FROM empWHERE n_dept = 10;
Exemple : Donner le nom, la fonction et le salaire de l'employé (ou des employés) ayant le salaire le plus élevé.
SELECT nom, fonction, salaireFROM empWHERE salaire = (SELECT MAX(salaire) FROM emp);
Remarques
Aucune des fonctions de groupe ne tient compte des valeurs NULL à l'exception de count(*). Ainsi, SUM(col) est la somme des valeurs non NULL de la colonne col. De même AVG est la somme des valeurs non NULL divisée par le nombre de valeurs non NULL.
Il est possible de subdiviser la table en groupes, chaque groupe étant l'ensemble des lignes ayant une valeur commune. C'est la clause GROUP BY qui permet de découper la table en plusieurs groupes :
GROUP BY expr_1, expr_2, ...
Si on a une seule expression, ceci définit les groupes comme les ensembles de lignes pour lesquelles cette expression prend la même valeur. Si plusieurs expressions sont présentes les groupes sont définis de la façon suivante : parmi toutes les lignes pour lesquelles
expr_1 prend la même valeur, on regroupe celles ayant expr_2 identique, ... Un SELECT de groupe avec une clause GROUP BY donnera une ligne résultat pour chaque groupe.
Exemple : Total des salaires pour chaque département
SELECT SUM(salaire), n_deptFROM empGROUP BY n_dept;
Remarque : Dans la liste des colonnes résultat d'un
SELECT comportant une fonction de groupe, ne peuvent figurer que des caractéristiques de groupe, c'est-à-dire :
De la même façon qu'il est possible de sélectionner certaines lignes au moyen de la clause
WHERE, il est possible dans un SELECT comportant une fonction de groupe de sélectionner par la clause HAVING, qui se place après la clause GROUP BY.Le prédicat dans la clause
HAVING suit les mêmes règles de syntaxe qu'un prédicat figurant dans une clause WHERE.Cependant, il ne peut porter que sur des caractéristiques du groupe : fonction de groupe ou expression figurant dans la clause
GROUP BY, dans ce cas la clause HAVING doit être placée après la clause GROUP BY.Exemple : Donner la liste des salaires moyens par fonction pour les groupes ayant plus de deux employés.
SELECT fonction,COUNT(*),AVG(salaire)FROM empGROUP BY fonctionHAVING COUNT(*) > 2;
Remarque : Un
SELECT de groupe peut contenir à la fois une clause WHERE et une clause HAVING. La clause WHERE sera d'abord appliquée pour sélectionner les lignes, puis les groupes seront constitués à partir des lignes sélectionnées, et les fonctions de groupe seront évaluées.Exemple : Donner le nombre d'ingénieurs ou de commerciaux des départements ayant au moins deux employés de ces catégories.
SELECT n_dept, COUNT(*)FROM empWHERE fonction in ('ingenieur','commercial')GROUP BY n_deptHAVING COUNT(*) >= 2;
Une clause
HAVING peut comporter une sous-interrogation.Exemple : Quel est le département ayant le plus d'employés?
SELECT n_dept,COUNT(*)FROM empGROUP BY n_deptHAVING COUNT(*) = (SELECT MAX(COUNT(*)) FROM emp GROUP BY n_dept) ;
Il est possible d'appliquer au résultat d'un
SELECT avec GROUP BY un deuxième niveau de fonction de groupe.Exemple : la fonction
MAX peut être appliquée aux nombres d'employés de chaque département pour obtenir le nombre d'employés du département ayant le plus d'employés.SELECT MAX(COUNT(*))FROM empGROUP BY n_dept ;
Le langage de manipulation de données est le langage permettant de modifier les informations contenues dans une base de données.
L'unité manipulée est la ligne. Il existe trois commandes SQL permettant d'effectuer les trois types de modifications des données : ajout, modification et suppression.
La commande
INSERT INTO nom_table(nom_col1, nom_col2, ...) VALUES (val1, val2...)
La liste des noms de colonne est optionnelle. Si elle est omise, la liste des colonnes sera par défaut la liste de l'ensemble des colonnes de la table dans l'ordre de la création de la table.
Si une liste de colonnes est spécifiée, les colonnes ne figurant pas dans la liste auront la valeur
Il est possible d'insérer dans une table des lignes provenant d'une autre table. La syntaxe est la suivante :
INSERT INTO nom_table(nom_col1, nom_col2, ...) SELECT ...
Le
SELECT peut contenir n'importe quelle clause sauf un ORDER BY qui impliquerait un classement des lignes contraire à l'esprit du relationnel.Exemple : Insérer dans la table bonus les noms et salaires des directeurs.
INSERT INTO bonus
SELECT nom, salaire
FROM emp
WHERE fonction = 'directeur';
INSERT INTO [schema.]table | view [ (column [, column] ...) ] VALUES (expr [, expr] ...) | subquery
nom des colonnes
Valeurs des colonnes
Pour pouvoir insérer des lignes dans une table il faut soit être propriétaire de cet objet, soit avoir le privilège
INSERT sur cette table.Le privilège
INSERT ANY TABLE permet d'insérer des lignes dans n'importe quelle table appartenant à n'importe quel utilisateur.
La commande
UPDATE permet de modifier les valeurs d'une ou plusieurs colonnes, dans une ou plusieurs lignes existantes d'une table. La syntaxe est la suivante :UPDATE nom_table SET nom_col1 = {expression1 | ( SELECT ...) }, nom_col2 = {expression2 | ( SELECT ...) } WHERE predicat
Les valeurs des colonnes
nom_col1, nom_col2, ... sont modifiées dans toutes les lignes satisfaisant au prédicat. En l'absence d'une clause WHERE, toutes les lignes sont mises à jour.Exemple : Augmenter de 10% les ingénieurs.
UPDATE emp
SET salaire = salaire * 1.1
WHERE fonction = 'ingenieur' ;
UPDATE [schema.]table | view [alias] SET (column [, column] ...) = (subquery) | column = expr | (subquery) [, (column [, column] ...) = (subquery) | column = expr | (subquery) ] ... [WHERE condition]
Pour pouvoir modifier des lignes appartenant à une table, il faut soit être propriétaire de cet objet, soit avoir le privilège UPDATE sur cette table.
le privilège UPDATE ANY TABLE permet de sélectionner des lignes de n'importe quel objet appartenant à n'importe quel utilisateur.
La commande
DELETE permet de supprimer des lignes d'une table.DELETE FROM nom_table WHERE prédicat ;
Toutes les lignes pour lesquelles
prédicat est évalué à vrai sont supprimées. En l'absence de clause WHERE, toutes les lignes de la table sont supprimées.DELETE [FROM] [schema.]table | view [alias] [WHERE condition]
Pour détruire des lignes appartenant à une table, il faut soit être propriétaire de la table, soit avoir le privilège DELETE sur cette table.
Le privilège DELETE ANY TABLE permet à un utilisateur de détruire des lignes se trouvant dans n'importe quelle table, ou n'importe quelle vue basée sur une table.
La commande DROP permet de détruire une table et toutes ses données.
DROP TABLE [schema.]table
[CASCADE CONSTRAINTS]
est le nom du schéma contenant la table ou la vue à détruire Le schéma par défaut est celui de l'utilisateur qui exécute la requête.
est le nom de la table à détruire.
CASCADE CONSTRAINTS
Supprime toutes les contraintes qui se refere à la table supprimée.
Prérequis
Pour pouvoir détruire une table il faut soit être propriétaire de cette table, soit avoir le privilège DROP ANY TABLE.
Une transaction est un ensemble de modifications de la base qui forme un tout indivisible. Il faut effectuer ces modifications entièrement ou pas du tout, sous peine de laisser la base dans un état incohérent.
Les Systèmes de Gestion de Bases de Données permettent aux utilisateurs de gérer leurs transactions. Ils peuvent à tout moment :
En cours de transaction, seul l'utilisateur ayant effectué les modifications les voit.
Ce mécanisme est utilisé par les systèmes de gestion de bases de données pour assurer l'intégrité de la base en cas de fin anormale d'une tâche utilisateur : il y a automatiquement
ROLLBACK des transactions non terminées.ORACLE est un système transactionnel qui assure la cohérence des données en cas de mise à jour de la base, même si plusieurs utilisateurs lisent ou modifient les mêmes données simultanément.
ORACLE utilise un mécanisme de verrouillage pour empêcher deux utilisateurs d'effectuer des transactions incompatibles et régler les problèmes pouvant survenir.
ORACLE permet le verrouillage de certaines unités (table ou ligne) automatiquement ou sur demande de l'utilisateur.
Les verrous sont libérés en fin de transaction.
Le langage de définition des données est le langage permettant de créer ou de modifier le schéma d'une relation et donc d'une table.
Il permet de créer, de modifier et de supprimer non seulement les tables, mais aussi les vues, les index et les clusters.
La table est la structure de base contenant les données des utilisateurs. Quand on crée une table, on peut spécifier les informations suivantes :
La commande de création de table la plus simple ne comportera que le nom et le type de chaque colonne de la table. L'on peut créer une table par la commande
CREATE TABLE en spécifiant le nom et le type de chaque colonne. A la création, la table sera vide mais un certain espace lui sera alloué. La syntaxe est la suivante :CREATE TABLE nom_table (nom_col1 TYPE1, nom_col2 TYPE2, ...)
L'option
NOT NULL assure qu'ORACLE interdit lors d'un INSERT ou d'un UPDATE que cette colonne contienne la valeur NULL, par défaut elle est autorisée.On peut insérer des données dans une table lors de sa création par la commande suivante :
CREATE TABLE nom_table [(nom_col1, nom_col2, ...)] AS SELECT...
On peut ainsi, en un seul ordre SQL créer une table et la remplir avec des données provenant du résultat d'un
SELECT.On n'a pas besoin alors de spécifier de type pour les colonnes : les types des données sont ceux provenant du
SELECT. Si des conversions de type sont à faire, on peut dans le SELECT utiliser les fonctions TO_CHAR, TO_DATE, TO_NUMBER.Par défaut les noms des colonnes de la nouvelle table sont les noms des colonnes du
SELECT. Si des expressions apparaissent dans le SELECT, les colonnes correspondantes doivent impérativement être renommées.Le
SELECT peut contenir des fonctions de groupes mais pas d'ORDER BY car les lignes d'une table ne peuvent pas être classées.On peut, et même on doit, quand on crée une table définir les contraintes d'intégrité que devront respecter les données que l'on mettra dans la table (voir un peu plus bas).
A la création d'une table, les contraintes d'intégrité se déclarent de la façon suivante :
CREATE TABLE nom_table ( nom_col_1 type_1, nom_col_2 type_2, ... nom_col_n type_n CONSTRAINT [nom_contrainte_1] contrainte_1, CONSTRAINT [nom_contrainte_2] contrainte_2, ... CONSTRAINT [nom_contrainte_m] contrainte_m );
Ou bien de la façon suivante :
CREATE TABLE nom_table ( nom_col_1 type_1 CONSTRAINT [nom_contrainte_1_1] contrainte_1_1 CONSTRAINT [nom_contrainte_1_2] contrainte_1_2 ... CONSTRAINT [nom_contrainte_1_m] contrainte_1_m, nom_col_2 type_2 CONSTRAINT [nom_contrainte_2_1] contrainte_2_1 CONSTRAINT [nom_contrainte_2_2] contrainte_2_2 ... CONSTRAINT [nom_contrainte_2_p] contrainte_2_p, ... nom_col_n type_n CONSTRAINT [nom_contrainte_n_1] contrainte_n_1 CONSTRAINT [nom_contrainte_n_2] contrainte_n_2 ... CONSTRAINT [nom_contrainte_n_q] contrainte_n_q );
Les contraintes différentes que l'on peut déclarer sont les suivantes :
On peut modifier dynamiquement la définition d'une table grâce a la commande
ALTER TABLE.Il n'est pas possible de supprimer une colonne. Par contre une colonne qui n'est plus utilisée peut être mise à la valeur
NULL, auquel cas elle n'occupe plus d'espace disque. Si on désire vraiment supprimer une colonne, il faut :La commande suivante permet d'ajouter une ou plusieurs colonnes à une table existante :
ALTER TABLE nom_table ADD (nom_col1 TYPE1, nom_col2 TYPE2, ...)
Les types possibles sont les mêmes que ceux décrits avec la commande
CREATE TABLE.Si la table contient déjà des lignes, la nouvelle colonne aura des valeurs
NULL pour les lignes existantes.Il est possible de modifier la définition d'une colonne, à condition que la nouvelle définition soit compatible avec le contenu de la colonne et en respectant les contraintes suivantes :
La commande
DROP TABLE permet de supprimer une table, sa syntaxe est la suivante :
DROP TABLE nom_table ;
La table
nom_table est alors supprimée. La définition de la table ainsi que son contenu sont détruits, et l'espace occupé par la table est libéré.Renommer une table
On a la possibilité de changer le nom d'une table par la commande
RENAME, la syntaxe est la suivante :RENAME ancien_nom TO nouveau_nom ;
Les vues permettent d'assurer l'objectif d'indépendance logique. Grâce à elles, chaque utilisateur pourra avoir sa vision propre des données.
On a vu que le résultat d'un
SELECT est lui-même une table.Les utilisateurs pourront consulter la base, ou modifier la base (avec certaines restrictions) à travers la vue, c'est-à-dire manipuler la table résultat du
SELECT comme si c'était une table réelle.Créer une vue
La commande
CREATE VIEW permet de créer une vue en spécifiant le SELECT constituant la définition de la vue :CREATE VIEW nom_vue [(nom_col1,...)] AS SELECT ... WITH CHECK OPTION ;
La spécification des noms de colonnes de la vue est facultative. Par défaut, les noms des colonnes de la vue sont les mêmes que les noms des colonnes résultat du
SELECT (si certaines colonnes résultat du SELECT sont des expressions, il faut renommer ces colonnes dans le SELECT, ou spécifier les noms de colonne de la vue).Une fois créée, une vue s'utilise comme une table. Il n'y a pas de duplication des informations mais stockage de la définition de la vue.
Exemple : Création d'une vue constituant une restriction de la table
emp aux employés du département 10.CREATE VIEW emp10 AS
SELECT *
FROM emp
WHERE n_dept = 10 ;
Le
CHECK OPTION permet de vérifier que la mise à jour ou l'insertion faite à travers la vue ne produisent que des lignes qui font partie de la sélection de la vue.Ainsi donc, si la vue
emp10 a été créée avec CHECK OPTION on ne pourra à travers cette vue ni modifier, ni insérer des employés ne faisant pas partie du département 10.Il est possible d'effectuer des
INSERT et des UPDATE à travers des vues, sous deux conditions :Exemple : Modification des salaires du département 10 à travers la vue
emp10.UPDATE emp10
SET sal = sal *1.1;
Toutes les lignes de la table emp, telles que le contenu de la colonne n_dept est égal à 10 seront modifiées.
Une vue peut être détruite par la commande :
DROP VIEW nom_vue;
On peut renommer une vue par la commande :
RENAME ancien_nom TO nouveau_nom;Introduction - Généralités
Selon le modèle relationnel les sélections peuvent être faites en utilisant le contenu de n'importe quelle colonne et les lignes sont stockées dans n'importe quel ordre.
Considérons le
SELECT suivant :SELECT * FROM emp WHERE nom = 'MARTIN'
Un moyen de retrouver la ou les lignes pour lesquelles ,font color=red>
nom est égal à MARTIN est de balayer toute la table.Un tel moyen d'accès conduit à des temps de réponse prohibitifs pour des tables dépassant quelques centaines de lignes.
Une solution offerte par tous les systèmes de gestion de bases de données est la création d'index, qui permettra de satisfaire aux requêtes les plus fréquentes avec des temps de réponse acceptables.
Un index sera matérialisé par la création de blocs disque contenant des couples (valeurs d'index, numéro de bloc) donnant le numéro de bloc disque dans lequel se trouvent les lignes correspondant à chaque valeur d'index.
Les index sont des structures permettant de retrouver une ligne dans une table à partir de la valeur d'une colonne ou d'un ensemble de colonnes. Un index contient la liste triée des valeurs des colonnes indexées avec les adresses des lignes (numéro de bloc dans la partition et numéro de ligne dans le bloc) correspondantes.
Tous les index oracle sont stockés sous forme d'arbres équilibrés (btree) : une structure arborescente permet de retrouver rapidement dans l'index la valeur de clé cherchée, et donc l'adresse de la ligne correspondante dans la table.
Dans un tel arbre, toutes les feuilles sont à la même profondeur, et donc la recherche prend approximativement le même temps quelle que soit la valeur de la clé.
Lorsqu'un bloc d'index est plein, il est éclaté en deux blocs. en conséquence, tous les blocs d'index ont un taux de remplissage variant de 50% à 100%. Sans index on balaie séquentiellement toute la table quelle que soit la position de élément recherché.
L'adjonction d'un index à une table ralentit les mises à jour (insertion, suppression, modification de la clé) mais accélère beaucoup la recherche d'une ligne dans la table.
L'index accélère la recherche d'une ligne à partir d'une valeur donnée de clé, mais aussi la recherche des lignes ayant une valeur d'index supérieure ou inférieure à une valeur donnée, car les valeurs de clés sont triées dans l'index.
Exemple : Les requêtes suivantes bénéficieront d'un index sur le champ
n_dept.SELECT * FROM emp WHERE num = 16034 ;
SELECT * FROM emp WHERE num >= 27234 ;
SELECT * FROM emp WHERE num BETWEEN 16034 AND 27234 ;
Un index est utilisable même si le critère de recherche est constitué seulement du début de la clé.
Exemple : La requête suivante bénéficiera d'un index sur la colonne
nom.SELECT *
FROM emp
WHERE nom LIKE 'M%' ;
Par contre si le début de la clé n'est pas connu, l'index est inutilisable.
Exemple : La requête suivante ne bénéficiera pas d'un index sur le champ
nom.SELECT *
FROM emp
WHERE ename LIKE '?????????' ;
Elles ne sont pas représentées dans l'index, ceci afin de minimiser le volume nécessaire pour stocker l'index. En contrepartie, l'index ne sera d'aucune utilité pour retrouver les valeurs NULL lorsque le critère de recherche est du type IS NULL.
L'index n'est utilisable que si le critère de sélection est le contenu de la colonne indexée, sans aucune transformation. Par exemple un index sur salaire ne sera pas utilisé pour la requête suivante :
SELECT * FROM emp
WHERE salaire * 12 > 300000 ;
Attention en particulier aux conversions de type qui peuvent empêcher l'utilisation de l'index.
SQL est un langage typé, chaque type de données (numérique, caractère, date) ayant ses propres opérateurs, ses propres fonctions et sa propre relation d'ordre. En conséquence, si dans une expression, figurent à la fois un nombre et une chaîne de caractères, SQL convertira la chaîne de caractères en nombre. De même si dans une expression, figurent à la fois une chaîne de caractères et une date, SQL convertira la chaîne de caractères en date.
Or, dans un prédicat du type :
WHERE fonction(col_indexée) = constante
SQL ne peut pas utiliser l'index.
Ceci peut se produire , de façon insidieuse, lorsque SQL est obligé d'ajouter un appel à une fonction de conversion à cause d'une discordance de type.
Exemple : Le prédicat suivant ne bénéficiera pas d'un index sur le champ
embauche.SELECT * FROM emp
WHERE embauche LIKE '????' ;
En effet, SQL est obligé d'effectuer une conversion, et le prédicat qui sera évalué est :
WHERE TO_CHAR(embauche) LIKE '????'
Le critère de recherche est une fonction de
embauche, et non le champ embauche lui-même, dans ce cas l'index est inutilisable.Indexer en priorité :
Ne pas indexer :
Créer un index
Un index peut être créé par la commande suivante :
CREATE [UNIQUE] INDEX nom_index ON nom_table (nom_col1 , nom_col2, ...) [PCTFREE nombre] [COMPRESS | NOCOMPRESS] [ROWS = nombre_lignes] ;
dans laquelle :
Un index peut être créé dynamiquement sur une table contenant déjà des lignes. Il sera ensuite tenu à jour automatiquement lors des modifications de la table.
Un index peut porter sur plusieurs colonnes, la clé d'accès sera alors la concaténation des différentes colonnes.
On peut créer plusieurs index indépendants sur une même table.
Les requêtes SQL sont transparentes au fait qu'il existe un index ou non. C'est l'optimiseur du système de gestion de bases de données qui, au moment de l'exécution de chaque requête, recherche s'il peut s'aider ou non d'un index.
Les clés dans les index peuvent être comprimées ou non. La compression est une technique permettant de réduire dans des proportions très importantes (d'autant plus que la clé est longue) le volume de l'index.
En contrepartie, il faut parfois un traitement supplémentaire pour recomposer la clé lors des mises à jour de l'index.
Par défaut, les index sont comprimés, les avantages de réduction de taille l'emportant sur les inconvénients dans la plupart des cas.
sql sait exécuter certaines requêtes directement au niveau de l'index sans passer par le segment de données, si l'index est non comprimé et si tous les champs résultats de la requête sont dans l'index.
Exemple : L'index crée par :
CREATE INDEX x
ON emp (num, nom)
nocompress ;
permettra de répondre à la question :
SELECT nom
FROM emp
WHERE num < 17217 ;
sans lire la table puisque toutes les informations se trouvent dans l'index et que l'index est non concaténé.
Un index concaténé est un index portant sur plusieurs colonnes.
Exemple :
CREATE INDEX xemp
ON (n_dept,num) ;
Les index concaténés peuvent être utilisés pour matérialiser une clé composée de plusieurs colonnes.
SQL sait utiliser un index concaténé même si le critère de recherche ne porte pas sur toutes les colonnes présentes dans l'index.
Exemple : L'index ci-dessus est utilisable si l'on ne connait que le numéro de département.
SELECT nom
FROM emp
WHERE n_dept = 20 ;
Un index peut être supprimé dynamiquement par la commande :
DROP INDEX nom_index;
L'espace libéré reste attaché au segment d'index de la table : il pourra être utilisé pour un autre index sur la même table.
L'espace ne sera rendu à la partition que lors de la suppression de la table.
Introduction - Généralités
Le cluster est une organisation physique des données qui consiste à regrouper physiquement (dans un même bloc disque) les lignes d'une ou plusieurs tables ayant une caractéristique commune (une même valeur dans une ou plusieurs colonnes) constituant la clé du cluster.
La mise en cluster a trois objectifs :
Le regroupement en cluster est totalement transparent à l'utilisateur : des tables mises en cluster sont toujours vues comme des tables indépendantes.
Par exemple on pourrait mettre en cluster les tables
emp et dept selon n_dept. Ces tables seraient réorganisées de la façon suivante : un bloc de cluster serait créé pour chaque numéro de département, ce bloc contenant à la fois les lignes de la table emp et de la table dept correspondant à ce numéro de département. La jointure entre les tables emp et dept selon n_dept deviendrait alors beaucoup plus rapide, puisqu'elle serait déjà réalisée dans l'organisation physique des tables.Pour que l'on puisse mettre une table en cluster il faut que l'une au moins des colonnes faisant partie du cluster soit définie comme obligatoire (
NOT NULL).On peut indexer les colonnes d'une table en cluster, y compris les colonnes correspondant à la clé ou à une partie de la clé du cluster. La clé elle-même est automatiquement indexée, on peut éventuellement la réindexer pour créer un index unique servant à contrôler son unicité.
Créer un cluster
Avant de pouvoir mettre en cluster une ou plusieurs tables il faut créer le cluster au moyen de la commande
CREATE CLUSTER dont la syntaxe est la suivante :CREATE CLUSTER nom_cluster (cle1 type1, cle2 type2, ...)
où l'on donne un nom au cluster, et où l'on définit le nom et le type des colonnes constituant la clé du cluster.
CREATE CLUSTER nom_cluster (cle1 type1, cle2 type2, ...) [SIZE taille_du_bloc] [COMPRESS | NOCOMPRESS] [SPACE nom_de_space_definition]
dans laquelle :
CREATE CLUSTER DEM (DEPNO NUMBER) SIZE 512 ;
En principe c'est dès sa création qu'il faut spécifier si une table sera implantée dans un cluster.
L'option cluster de l'ordre
CREATE TABLE permet de spécifier que la table doit être mise en cluster. Le cluster doit déjà exister.CREATE TABLE nom_table (nom_col1 TYPE1 NOT NULL , (nom_col2 TYPE2 NOT NULL , ...) CLUSTER NOM_CLUSTER (nom_coli, nom_colj...)
nom_coli, nom_colj sont des noms de colonnes de la table, elles seront identifiées une à une aux colonnes clés du cluster spécifiées à la création du cluster.
En principe cela n'est pas possible, il faut donc procéder de la façon suivante :
Pour retirer une table d'un cluster il faut :
ceci ne détruit pas la table, mais la reconstruit en dehors du cluster.
Supprimer un cluster
Un cluster ne contenant aucune table peut être supprimé par la commande :
DROP CLUSTER nom_cluster ;
Remarque :
Les performances du cluster ne sont valables que si on n'a pas de blocs chaînés (ex de grande table).
© 1999/05 - ThC