Vous êtes sur la page 1sur 14

Les + du SQL de la 9i

Ce document liste quelques nouvelles fonctionalités du SQL des versions 8i et 9i d'Oracle vues du coté
developpement.
Toutes les nouveautés ne sont pas abordées mais seulement celles dont le rapport efficacité/mise en oeuvre
semble le plus interessant.
Beaucoup de composant du SQL découlent de la prise en charge de la norme SQL 1999 et de ce fait certaines
expressions sont redondantes par rapport à des synthaxes qui existaient déjà.
Remarques :
Toutes les commandes listées dans ce document ont été testées.
Ce document a été crée avec la suite libre OpenOffice.

Sommaire
1 - Types de données ...............................................................................................................................................1
2 - Fonctions SQL (intéressantes)............................................................................................................................2
3 - DDL....................................................................................................................................................................4
4 - DSL (Select) .......................................................................................................................................................8
5 - DSL : Fonctions analytiques...............................................................................................................................9
6 - DML..................................................................................................................................................................13

1 - Types de données
Les types classiques sont maintenus avec des améliorations (varchar2 peut contenir jusqu'à 4000 octets).
Le type LONG ne devra plus être utilisé mais remplace par CLOB (jusqu'à 4G) pour contenir des données non
structurées du type texte word, image, video...
A noter que la plupart des fonctions de traitement de caractères ne fonctionnent pas sur les champs de type
LONG ou LOB. Il y a également d'autres restrictions qui conduisent à penser que ce type de champ devra être
utilisé seulement quand la limite de VARCHAR2 est atteinte.
De même LONG RAW est remplace par BLOB pour stocker du binaire.
BFILE sert a stocker un pointeur sur un fichier du serveur.
TIMESTAMP est une extension du type date comportant notament les fractions de secondes et la gestion des
fuseaux horaire (clause WITH TIME ZONE ).

Enfin la 8i a introduit la notion de type qui permet à chacun de créer ses propres types.
Nous ne parlerons pas ici de ces extentions objets utilisées principalement par les logiciels Oracle.

DSIT/SASE/DBA - Les + de la 9i – Chme Nov 2004 – version 1.0.a.0.1 page Numéro de page/Statistiques
2 - Fonctions SQL (intéressantes)
Expression CASE
SELECT VILLE,CASE NOVILLE
WHEN 10 THEN 'AIX-EN-PROVENCE'
ELSE VILLE
END AS "APELLATION OFFICIELLE"
FROM HABITE
est équivalent à :
select ville, decode(noville,10,'Aix-en-Provence',ville) "Apellation officielle" from
habite
mais c'est plus clair...
La clause WHEN peut être suivie d'un prédicat et cette synthaxe apporte plus :
SELECT ENAME,CASE
WHEN ENAME LIKE 'J%' THEN 'SDF'
ELSE (SELECT VILLE FROM HABITE A WHERE B.NOVILLE = A.NOVILLE)
END AS "DOMICILE"
FROM EMP B
bien sûr cette requête est équivalente à :
SELECT ENAME, NVL(VILLE,'SDF') "DOMICILE" FROM EMP NATURAL LEFT JOIN HABITE
Autre exemple :

SELECT SAL, CASE WHEN SAL < 2000 THEN 'PAUVRE'


WHEN SAL < 3000 THEN 'MOYEN'
WHEN SAL < 4000 THEN 'RICHE'
ELSE 'BILL'
END
FROM EMP

NULLIF : exemple
SQL> set null 'GROS NUL'
SQL> SELECT NULLIF('A EST EGAL A B','A ET B') FROM DUAL;
NULLIF('AESTEG
--------------
A est egal a B
Le premier parametre de la fonction nullif n'est pas egal au second donc il est retourné.
SQL> SELECT NULLIF('A EST EGAL A B','A EST EGAL A B') FROM DUAL;
NULLIF('AESTEG
--------------
GROS NUL
Les 2 parametres sont égaux, c'est null qui est retouné.

COALESCE = NVL
SELECT COALESCE(NULL,'BIEN NUL') FROM DUAL;
COALESCE
--------
BIEN NUL
(compatibilité norme SQL)

NVL2
plus interessante que nvl qui n'avait que 2 arguments, NVL2 en a 3 mais retourne toujours du varchar2
EXEMPLE > SELECT NVL2(COMM,'RIEN','BEAUCOUP') FROM EMP;

NVL2(COM
--------
beaucoup
Rien
Rien
beaucoup

DSIT/SASE/DBA - Les + de la 9i – Chme Nov 2004 – version 1.0.a.0.1 page Numéro de page/Statistiques
current_date et current_timestamp,systimestamp
EXEMPLE > SELECT CURRENT_DATE FROM DUAL;

CURRENT_D
---------
05-OCT-04

Exemple > select current_timestamp from dual;

CURRENT_TIMESTAMP
---------------------------------------------------------------------------
05-OCT-04 04.02.33.152885 PM +02:00

Exemple > select systimestamp from dual;

SYSTIMESTAMP
---------------------------------------------------------------------------
05-OCT-04 04.52.00.443615 PM +02:00

extract
Cette fonction permet de remplacer la fonction to_char mais avec une synthaxe plus facile.
EXEMPLE > SELECT EXTRACT(MONTH FROM SYSDATE) FROM DUAL;

EXTRACT(MONTHFROMSYSDATE)
-------------------------
10

Exemple > select extract(year from sysdate) from dual;

EXTRACT(YEARFROMSYSDATE)
------------------------
2004

sys_context
Cette fonction remplace userenv et elle est beaucoup plus riche :
EXEMPLE > SELECT SYS_CONTEXT('USERENV','IP_ADDRESS') "@IP" FROM DUAL;

@ip
10.1.100.32

Exemple > select sys_context('USERENV','LANG') Language from dual;

LANGUAGE
US

select sys_context('USERENV','DB_NAME') "Nom de la base" from dual;

Nom de la base
devde

Exemple > select sys_context('USERENV','HOST') "Client" from dual;

Client
cmenaldo.dsi-hd13

Exemple > select sys_context('USERENV','OS_USER') "OS_USER" from dual;

OS_USER
cmenaldo
Plein d'autres arguments sont acceptés en paramêtre. Voir la doc.

Trim
Combinaison de RTRIM et LTRIM
SELECT TRIM(' LIBELLE ') AS LIB FROM DUAL;

LIB
-------
libelle

DSIT/SASE/DBA - Les + de la 9i – Chme Nov 2004 – version 1.0.a.0.1 page Numéro de page/Statistiques
Ou nouvelle synthaxe :
SQL> select trim(leading '=' from '=============libelle==========') as lib from dual;

LIB
-----------------
libelle==========

SQL> select trim(both '=' from '=============libelle==========') as lib from dual;

LIB
-------
libelle

3 - DDL
Colonnes
Renomage d'une colonne :
ALTER TABLE HABITE RENAME COLUMN NOVILLE TO NVILLE;

Cet ordre a pour conséquence d'invalider les triggers, procédures, fonctions... et autres vues portant sur la
colonne concernée. Cette remarque s'applque aussi pour la commande suivante.

Suppression d'une colonne :


ALTER TABLE HABITE2 DROP COLUMN MAJ;

Renommage d'une constrainte :


ALTER TABLE HABITE RENAME CONSTRAINT NO_VILLE TO PK_HABITE;

index explicite
Jusqu'à présent :
CREATE TABLE "CHM"."HABITE2"
( "NOVILLE" NUMBER,
"VILLE" VARCHAR2(50),
"REGION" VARCHAR2(10),
CONSTRAINT "NO_VILLE2" PRIMARY KEY ("NOVILLE")
USING INDEX PK_HABITE2)
donnait :
CREATE TABLE "CHM"."HABITE2"
*
ERREUR a la ligne 1 :
ORA-01418: specified index does not exist
En enlevant le nom de l'index la commande devient valide mais l'index resultant de cette commande se nome
comme la contrainte.

CREATE TABLE "CHM"."HABITE2"


( "NOVILLE" NUMBER,
"VILLE" VARCHAR2(50),
"REGION" VARCHAR2(10),
CONSTRAINT "NO_VILLE2" PRIMARY KEY ("NOVILLE")
USING INDEX (CREATE INDEX IDX_NOVILLE ON HABITE2(NOVILLE)))

Maintenant le nom de l'index et celui de la contrainte sont différents et de plus on peut utiliser la synthaxe
habituelle du create index pour appliquer les clauses comme tablespace, parallel...
autre exemple plus interessant :

CREATE TABLE "CHM"."HABITE2"


( "NOVILLE" NUMBER,
"VILLE" VARCHAR2(50),
"REGION" VARCHAR2(10),
CONSTRAINT "NO_VILLE2" PRIMARY KEY ("NOVILLE")
USING INDEX (CREATE INDEX IDX_NOVILLE ON HABITE2(NOVILLE,REGION)));

La commande suivante permet de dropper l'index en même temps que la contrainte :

DSIT/SASE/DBA - Les + de la 9i – Chme Nov 2004 – version 1.0.a.0.1 page Numéro de page/Statistiques
ALTER TABLE HABITE2 DROP CONSTRAINT NO_VILLE2 DROP INDEX;

Le drop peut être remplacé par KEEP alors l'index n'est pas supprimé.

Tables temporaires
Ce sont des tables qui ne vivent (au plus) que le temps d'une session. Elle sont vidées à la fin de chaque session
ou a chaque fin de transaction si la clause on commit preserve rows n'est pas spécifiée.
Une session concurente voit la table mais uniquement les lignes qu'elle a créée elle même.
Elle peuvent donc être tres utililes pour contenir des données propre à chaque sessions.
SQL> CREATE GLOBAL TEMPORARY TABLE TEMPO
2 ON COMMIT PRESERVE ROWS
3 AS SELECT ENAME FROM EMP;

Table created.

SQL>
SQL> select count(*) from tempo;

COUNT(*)
----------
14

SQL> disconnect
Disconnected from Oracle9i Enterprise Edition Release 9.2.0.5.0 - 64bit Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.5.0 - Production
SQL> connect chm/chm@devde
Connected.
SQL> /

COUNT(*)
----------
0

IOT : tables organisées en index


Cette nouvelle fonctionalité permet d'économiser la place d'un index quand celui-ci par exemple s'appuie sur
toutes les colonnes de la table. Cette fonctionalité a été présentée par Oracle comme améliorant les temps
d'accés. Les tests que j'ai pu faire ainsi que quelques discussions sur le net tendent à prouver le contraire.
De plus il n'y a aucun apport fonctionnel.
Contrainte : il faut que la table ait une clé primaire.
SQL> set timing on
SQL> CREATE TABLE IOT (INSTANCE , UTIL_OS, NBTOT ,PRIMARY KEY (INSTANCE,UTIL_OS))
ORGANIZATION INDEX
AS (SELECT INSTANCE,UTIL_OS,SUM(NBRE) NBTOT FROM CONNEXIONS GROUP BY
INSTANCE,UTIL_OS) ;
Table created.
Elapsed: 00:00:00.30
SQL> create table non_iot (INSTANCE , UTIL_OS, NBTOT ,primary key (instance,util_os))
2 as (select instance,util_os,sum(nbre) nbtot from connexions group by
instance,util_os);

Table created.
Elapsed: 00:00:00.46
SQL> select count(*) from iot;

COUNT(*)
----------
1334
Elapsed: 00:00:00.03
SQL> select count(*) from non_iot;

COUNT(*)
----------
1334
Elapsed: 00:00:00.03
SQL> select count(*) from iot where instance='PRDUN' and util_os like 'cme%';

COUNT(*)
----------

DSIT/SASE/DBA - Les + de la 9i – Chme Nov 2004 – version 1.0.a.0.1 page Numéro de page/Statistiques
1

Elapsed: 00:00:00.01
SQL> select count(*) from non_iot where instance='PRDUN' and util_os like 'cme%';

COUNT(*)
----------
1

Elapsed: 00:00:00.01
SQL> select nbtot from iot where instance='PRDUN' and util_os like 'cme%';

NBTOT
----------
770

Elapsed: 00:00:00.01
SQL> select nbtot from non_iot where instance='PRDUN' and util_os like 'cme%';

NBTOT
----------
770

Elapsed: 00:00:00.01

Tables externes
On peut désormais déclarer une tables « externe » c'est à dire un fichier qui est sur le serveur sur lequel tourne la
base. Pour mémoire le package PL/SQL UTL_FILE permet lui aussi le traitement des fichiers (lecture+écriture).
La synthaxe de declaration est analogue à celle de SQL*Loader et seule la lecture est permise sur ces tables.
Exemple :
Creation du fichier (sur le serveur) :
cd /tmp
cat >tabext
7369,SMITH,CLERK,20
7499,ALLEN,SALESMAN,30
7521,WARD,SALESMAN,30
7566,JONES,MANAGER,20
7654,MARTIN,SALESMAN,30

Déclaration de la « directory » et des droits (effectué par l'administrateur ) :


SQL> CREATE OR REPLACE DIRECTORY ext AS '/tmp';
Directory created.
GRANT READ ON DIRECTORY ext TO scott;
GRANT WRITE ON DIRECTORY ext TO scott;
(Malgré ce privilège, la table extene ne sera utilisable qu'en lecture.)
Creation de la table externe (par l'utilisateur) :

1 CREATE TABLE EXT_TAB (


2 EMPNO CHAR(4),
3 ENAME CHAR(20),
4 JOB CHAR(20),
5 DEPTNO CHAR(2))
6 ORGANIZATION EXTERNAL
7 (TYPE ORACLE_LOADER
8 DEFAULT DIRECTORY EXT
9 ACCESS PARAMETERS
10 (FIELDS TERMINATED BY ','
11 MISSING FIELD VALUES ARE NULL
12 (EMPNO, ENAME, JOB, DEPTNO))
13 LOCATION ('TABEXT')
14* )

Table created.
SQL> select TABLE_NAME, DEFAULT_DIRECTORY_NAME from user_external_tables;

TABLE_NAME DEFAULT_DIRECTORY_NAME
------------------------------ ------------------------------
EXT_TAB EXT
SQL> select ename from ext_tab;

ENAME

DSIT/SASE/DBA - Les + de la 9i – Chme Nov 2004 – version 1.0.a.0.1 page Numéro de page/Statistiques
--------------------
SMITH
ALLEN
WARD
JONES
MARTIN

SQL> desc ext_tab;


Name Null? Type
----------------------------------------- -------- ----------------------------
EMPNO CHAR(4)
ENAME CHAR(20)
JOB CHAR(20)
DEPTNO CHAR(2)

SQL> update ext_tab set deptno=null;


update ext_tab set deptno=null
*
ERROR at line 1:
ORA-30657: operation not supported on external organized table

DSIT/SASE/DBA - Les + de la 9i – Chme Nov 2004 – version 1.0.a.0.1 page Numéro de page/Statistiques
4 - DSL (Select)
Sous-interrogation scalaire
Integration d'une requête à la place d'un champ.
La commande suivante
SELECT DNAME DEPARTEMENT,
(SELECT COUNT(*) FROM EMP E WHERE E.DEPTNO=D.DEPTNO) AS "NOMBRE D'EMPLOYES"
FROM DEPT D;

est équivalente à :

select dname as departement, nvl(nb,0) as "Nombre d'employes"


from dept d, (select deptno, count(*) nb from emp group by deptno) e
where e.deptno(+)=d.deptno;

Nouvelle synthaxe du select : clause JOIN


Produit cartésien (à utiliser avec modération !) :
select * from emp,dept
devient :

SELECT * FROM EMP CROSS JOIN DEPT

Equijointure
select a.deptno,a.ename from emp a,dept b where a.deptno = b.deptno
devient :
SELECT DEPTNO,ENAME FROM EMP JOIN DEPT USING (DEPTNO)

Contrainte : les 2 tables ont en commun le même nom de champ


autre exemple :
select deptno,ename from emp join dept using (deptno) where deptno = 10
remplace :
SELECT A.DEPTNO,A.ENAME FROM EMP A,DEPT B WHERE A.DEPTNO = B.DEPTNO AND A.DEPTNO = 10

Nouvelle synthaxe : clause ON


Elle sépare les prédicats de jointure des autres :
SELECT A.DEPTNO,A.ENAME
FROM EMP A JOIN DEPT B ON A.DEPTNO = B.DEPTNO
WHERE A.DEPTNO = 10

Cette requête est equivalente à la précédente mais plus lisible.


La synthaxe peut paraître équivalente à celle de la clause USING. La différence est que la il y a prédicat (donc
présence d'un opérateur) alors qu'avec USING on mentionne seulement le nom de la colonne.
Ce type de synthaxe s'étend à plusieurs tables :
Préparation :
create table habite (noville number, ville varchar2(50));
alter table emp add (noville number);
insert into habite values (10 , 'AIX')
insert into habite values (20 , 'Marseille')
insert into habite values (30 , 'La Ciotat')
update emp set noville = mod(rownum*10,30)+10
commit;
requête :
SELECT DEPTNO,ENAME,VILLE FROM EMP JOIN DEPT USING (DEPTNO) JOIN HABITE USING
(NOVILLE)
Jointures naturelles :
SELECT DNAME ,ENAME, VILLE FROM EMP NATURAL JOIN DEPT NATURAL JOIN HABITE

DSIT/SASE/DBA - Les + de la 9i – Chme Nov 2004 – version 1.0.a.0.1 page Numéro de page/Statistiques
La conditionn nécéssaire est que les noms de colonnes sur lesquels reposent les jointures soient les identiques et
de même type.
Jointures externes :
update emp set noville = null where ename like 'J%'
Jones et James n'ont plus de noville.
Avec la requête suivante ils apparaissent quand même :
SELECT ENAME, DNAME , VILLE FROM EMP NATURAL JOIN DEPT NATURAL LEFT JOIN HABITE ORDER
BY 1
Ainsi les mot-clés left, right et full remplacent les (+) qui étaient fastidieux à positionner.
insert into habite values (40,'Aubagne')
SELECT ENAME, VILLE FROM EMP NATURAL RIGHT JOIN HABITE ORDER BY 1
ramène la ligne « Aubagne » mais pas « Jones » ni « James »
SELECT ENAME, VILLE FROM EMP NATURAL FULL JOIN HABITE ORDER BY 1
ramène toutes les lignes des 2 tables.

Clause WITH
Elle permet de n'executer qu'une seule fois une sous-requête dans une interrogation :
exemple :
Pour trouver dans le mois le jour ou il y a le plus et le moins de connexions :

WITH SOMME AS (SELECT TO_CHAR(DATE_CONN,'DD') JOUR , SUM(NBRE) NOMBRE


FROM CONNEXIONS GROUP BY TO_CHAR(DATE_CONN,'DD'))
SELECT 'MINI ',JOUR ,A.NB
FROM (SELECT MIN(NOMBRE) NB FROM SOMME) A ,SOMME B
WHERE A.NB = B.NOMBRE
UNION
SELECT 'MOYENNE PAR JOUR','DU MOIS ' , ROUND(AVG(NOMBRE))
FROM SOMME
UNION
SELECT 'MAX',JOUR ,A.NB
FROM (SELECT MAX(NOMBRE) NB FROM SOMME) A ,SOMME B
WHERE A.NB = B.NOMBRE

avant la 9i , qu'aurais-je écrit et surtout comment cela ce serait-il passé au niveau de l'optimiseur ?

Insert multitable
Permet d'inserer des lignes dans différentes tables à partir d'une requête. Bien sur cet ordre ne gère pas les
doubles sur la clé primaire.
préparation :
create table utilHD13 as select util_os,resolution_ip from connexions where 1 =2
create table util_hors_HD13 as select util_os,resolution_ip from connexions where 1 =2

INSERT WHEN INSTR(RESOLUTION_IP,'HD13') <> 0 THEN INTO UTILHD13


ELSE INTO UTIL_HORS_HD13
SELECT UTIL_OS,RESOLUTION_IP FROM CONNEXIONS WHERE ROWNUM < 1000

Ici on insère dans 2 tables différentes suivant que la colonne RESOLUTION_IP contient ou non 'hd13'.
On peut indiquer à la place du else une autre condition.
Cet ordre semble interessant pour créer plusieurs tables simultanéement en ne faisant qu'une lecture de la table
d'origine. Celle-ci peut d'ailleurs être une table externe. Par contre il faudra faire attention aux contraintes des
tables cibles et notament celles de clé primaires.

5 - DSL : Fonctions analytiques


Un certain nombre de fonctions statistiques sont aparues en 8i et 9i pour completer celles qui existaient déjà.
Elles ont pour but d'offrir de meilleures performances aux outils décisionnels d'Oracle mais peuvent aussi être
utilisées par le sqlman moyen. Nous verrons ici que les plus simples...

DSIT/SASE/DBA - Les + de la 9i – Chme Nov 2004 – version 1.0.a.0.1 page Numéro de page/Statistiques
WITH_BUCKET
permet d'affecter un intervalle auquel le resultat d'une expression d'entrée est affectée apres son evaluation
Soit la table connexions (pres de 20000 lignes)
SQL> desc connexions
Name Null? Type
----------------------------------------- -------- ----------------------------
DATE_CONN DATE
INSTANCE VARCHAR2(12)
UTIL_OS VARCHAR2(50)
RESOLUTION_IP VARCHAR2(50)
PROGRAMME VARCHAR2(100)
NBRE NUMBER

SELECT INSTANCE, SUM(NBRE) NB, WIDTH_BUCKET (SUM(NBRE),1000,20000,5) INTER FROM


CONNEXIONS GROUP BY INSTANCE;

Résultat:
INSTANCE NB INTER
------------ ---------- ----------
DEVUN 9475 3
FORTR 1150 1
INFUN 13823 4
PPRDE 3922 1
PPRQU 795 0
PPRTR 909 0
PPRUN 858 0
PRDUN 16547 5
PROCI 22981 6
PROQU 14453 4
PROTR 22036 6

INSTANCE NB INTER
------------ ---------- ----------
TESQU 553 0
TESUN 5951 2
WWWUN 1697 1

14 rows selected.
Cette fonction permet d'affecter un poids à chaque ligne :
Le premier caractère indique le champs sur lequel s'applique la fonction, puis la limite inférieure, la limite
supérieure et le nombre de «tranches».

DSIT/SASE/DBA - Les + de la 9i – Chme Nov 2004 – version 1.0.a.0.1 page Numéro de page/Statistiques
Regroupement d'ensemble
En une seule requête, il est possible de faire plus et plus performant qu'avec la clause group by.
Ex : clause group by simple
SQL> select instance,util_os,programme,sum(nbre)from connexions where nbre >100 group
by instance,util_os,programme;

INSTANCE UTIL_OS PROGRAMME SUM(NBRE)


------------ ------------------ ------------------ ----------
DEVUN SYSTEM php.exe 1593
...
INFUN intranet 9788
PRDUN CRAVIN lims.exe 240
PROCI VATEND spdinstr.exe 431
PROCI MBALLY spdinstr.exe 369
...
PROCI NFIGORITO spdinstr.exe 108
PROCI LIEGBIGO spdinstr.exe 134
PROQU intranet 6032
TESUN GAT1 ifrun60.exe 359
TESUN ZOWNIAKO ifcmp60.exe 217
TESUN ZOWNIAKO rwcon60.exe 616

21 rows selected.

Clause group by rollup : permet d'avoir les sous-totaux dans une clause group by pour chaque niveau de rupture
ainsi qu'un total général. Cela est donc pratique pour generer des tableaux avec total par ligne et par colonne.

SQL> set NULL "Total ==>"


SQL> select instance,util_os,programme,sum(nbre)from connexions where nbre >100
2 group by rollup (instance,util_os,programme)
3 /

INSTANCE UTIL_OS PROGRAMME SUM(NBRE)


------------ ------------------ ------------------ ----------
DEVUN SYSTEM php.exe 1593
DEVUN SYSTEM Total ==> 1593
DEVUN JTIERS vb.exe 101
DEVUN JTIERS Total ==> 101
DEVUN TestNT4 apache.exe 164
DEVUN TestNT4 Total ==> 164
DEVUN Total ==> Total ==> 1858
...
TESUN ZOWNIAKO rwcon60.exe 616
TESUN ZOWNIAKO Total ==> 833
TESUN Total ==> Total ==> 1192
Total ==> Total ==> Total ==> 22149

48 rows selected.
Note : ici on ne fait pas de différence entre la valeur nulle située dans les données et celle renvoyée par la
clause ROLLUP. Il existe la fonction GROUPING qui permet de faire cette différence.Elle renvoie la valeur 1 si
le null est le résultat de la fonction.
Ainsi la requête aurrait pu s'écrire :
SELECT DECODE(GROUPING(INSTANCE),1,'TOTAL INSTANCE',INSTANCE) INSTANCE,
DECODE(GROUPING(UTIL_OS),1,'TOTAL USER',UTIL_OS) UTILISATEUR,
DECODE(GROUPING(PROGRAMME),1,'TOTAL PRG',PROGRAMME) PRG,
SUM(NBRE)
FROM CONNEXIONS WHERE NBRE >100
GROUP BY ROLLUP (INSTANCE,UTIL_OS,PROGRAMME)

...
TESUN GAT1 Total prg 359
TESUN ZOWNIAKO ifcmp60.exe 217

INSTANCE UTILISATEUR PRG SUM(NBRE)


-------------- ------------------ ------------------ ----------
TESUN ZOWNIAKO rwcon60.exe 616
TESUN ZOWNIAKO Total prg 833
TESUN Total User Total prg 1192
Total instance Total User Total prg 22149

DSIT/SASE/DBA - Les + de la 9i – Chme Nov 2004 – version 1.0.a.0.1 page Numéro de page/Statistiques
48 rows selected.

Group by CUBE :
Cette clause permet de calculer tous les sous-totaux pour chaque combinaison possible de colonne :
SQL> select instance,util_os,programme,sum(nbre)from connexions where nbre >100
2 group by cube (instance,util_os,programme)
3 /

INSTANCE UTIL_OS PROGRAMME SUM(NBRE)


------------ ------------------ ------------------ ----------
Total ==> Total ==> Total ==> 22149
...
Total ==> Total ==> rwcon60.exe 616
Total ==> Total ==> spdinstr.exe 2786

INSTANCE UTIL_OS PROGRAMME SUM(NBRE)


------------ ------------------ ------------------ ----------
Total ==> GAT1 Total ==> 359
Total ==> GAT1 ifrun60.exe 359
...
DEVUN Total ==> apache.exe 164
DEVUN SYSTEM Total ==> 1593

INSTANCE UTIL_OS PROGRAMME SUM(NBRE)


------------ ------------------ ------------------ ----------
DEVUN SYSTEM php.exe 1593
...

INSTANCE UTIL_OS PROGRAMME SUM(NBRE)


------------ ------------------ ------------------ ----------
TESUN Total ==> Total ==> 1192
TESUN Total ==> ifcmp60.exe 217
TESUN Total ==> ifrun60.exe 359
TESUN Total ==> rwcon60.exe 616
TESUN GAT1 Total ==> 359
TESUN GAT1 ifrun60.exe 359
TESUN ZOWNIAKO Total ==> 833
TESUN ZOWNIAKO ifcmp60.exe 217
TESUN ZOWNIAKO rwcon60.exe 616

108 rows selected.

La nouvelle clause GROUPING SET permet d'identifier que les groupes interessants :

SQL> select instance,util_os,programme,sum(nbre)from connexions where nbre >100


2 group by grouping sets (instance,util_os,programme);

INSTANCE UTIL_OS PROGRAMME SUM(NBRE)


------------ ------------------ ------------------ ----------
DEVUN Total ==> Total ==> 1858
...
TESUN Total ==> Total ==> 1192
Total ==> ZOWNIAKO Total ==> 833
...
Total ==> Total ==> 15820
Total ==> Total ==> apache.exe 164
Total ==> Total ==> ifcmp60.exe 217
...
Total ==> Total ==> spdinstr.exe 2786
Total ==> Total ==> vb.exe 101

35 rows selected.
Ou encore :
SQL> select instance,util_os,programme,sum(nbre)from connexions where nbre >100
2 group by grouping sets (instance,util_os,programme)
3 , (util_os,programme);

INSTANCE UTIL_OS PROGRAMME SUM(NBRE)


------------ ------------------ ------------------ ----------
TESUN GAT1 ifrun60.exe 359
PROCI VATEND spdinstr.exe 431
PROCI MBALLY spdinstr.exe 369
...
PROCI LIEGBIGO spdinstr.exe 134

DSIT/SASE/DBA - Les + de la 9i – Chme Nov 2004 – version 1.0.a.0.1 page Numéro de page/Statistiques
Total ==> GAT1 ifrun60.exe 359

...
Total ==> NFIGORITO spdinstr.exe 108
Total ==> LIEGBIGO spdinstr.exe 134

61 rows selected.

Les différentes clauses peuvent être combinées entre elles :


SQL> l
1 select instance,util_os,programme,sum(nbre)from connexions where nbre >100
2 group by instance,
3 cube (util_os),
4* rollup(programme)
SQL> /

INSTANCE UTIL_OS PROGRAMME SUM(NBRE)


------------ ------------------ ------------------ ----------
DEVUN JTIERS vb.exe 101
DEVUN SYSTEM php.exe 1593
DEVUN TestNT4 apache.exe 164
INFUN intranet 9788
INFUN SAISIE2 pel.exe 253
PRDUN CRAVIN lims.exe 240
PROCI VATEND spdinstr.exe 431
...
PROCI LIEGBIGO spdinstr.exe 134
PROQU intranet 6032
TESUN ZOWNIAKO ifcmp60.exe 217
TESUN GAT1 ifrun60.exe 359
TESUN ZOWNIAKO rwcon60.exe 616
DEVUN Total ==> vb.exe 101
...
DEVUN Total ==> apache.exe 164
INFUN Total ==> 9788
INFUN Total ==> pel.exe 253
PRDUN Total ==> lims.exe 240
PROCI Total ==> spdinstr.exe 2786
PROQU Total ==> 6032
TESUN Total ==> ifcmp60.exe 217
TESUN Total ==> ifrun60.exe 359
TESUN Total ==> rwcon60.exe 616
DEVUN SYSTEM Total ==> 1593

...
DEVUN Total ==> Total ==> 1858
INFUN SAISIE2 Total ==> 253
INFUN intranet Total ==> 9788
INFUN Total ==> Total ==> 10041
PRDUN CRAVIN Total ==> 240
PRDUN Total ==> Total ==> 240
PROCI VATEND Total ==> 431
...
PROCI LIEGBIGO Total ==> 134
PROCI Total ==> Total ==> 2786
PROQU intranet Total ==> 6032
PROQU Total ==> Total ==> 6032

INSTANCE UTIL_OS PROGRAMME SUM(NBRE)


------------ ------------------ ------------------ ----------
TESUN GAT1 Total ==> 359
TESUN ZOWNIAKO Total ==> 833
TESUN Total ==> Total ==> 1192

58 rows selected.

De nombreuses autres fonctions analytiques existent dans Oracle mais elles s'adressent à des spécialistes.

6 - DML
Mot clé « DEFAULT » dans Update.
alter table habite add (region varchar2(10) default 'Paca')
UPDATE HABITE SET REGION = DEFAULT

DSIT/SASE/DBA - Les + de la 9i – Chme Nov 2004 – version 1.0.a.0.1 page Numéro de page/Statistiques
MERGE
Permet de faire de la mise à jour de table ou de la création avec un seul ordre SQL...à essayer !
Preparation :
alter table habite add (constraint no_ville primary key ( noville))
create table habite2 as select * from habite where noville < 30
alter table habite2 add (constraint no_ville2 primary key ( noville));
alter table habite add (maj varchar2(3) default 'Ok')
Ordre :
MERGE INTO HABITE2 A USING HABITE B ON ( A.NOVILLE = B.NOVILLE)
WHEN MATCHED THEN UPDATE SET A.VILLE = B.VILLE
WHEN NOT MATCHED THEN INSERT (A.NOVILLE,A.VILLE,A.REGION ) VALUES
(B.NOVILLE,B.VILLE,B.REGION);
Contraintes :
Les 2 tables doivent avoir une clé primaire sur la colonne utilisée dans la clause ON.
Les 2 clauses WHEN sont obligatoires.
Pour chaque ligne de la table HABITE la ligne correspondante est recherchée sur HABITE2 via la clause on.
En fonction de la correspondance l'une des clauses when est executée.
La table HABITE peut être une table externe.

Pour plus de précisions, voir la doc Oracle9i SQL

DSIT/SASE/DBA - Les + de la 9i – Chme Nov 2004 – version 1.0.a.0.1 page Numéro de page/Statistiques