Entrepôts de Données
Introduction
Pour remplir un entrepot de données, il faut :
* une étape d’extraction (des données pertinentes des les bases de production) ;
* une étape de transformation (nettoyage, formattage, premières agrégations et reconnaissance des membres) ;
* une étape de chargement (des données propres dans la base décisionnelle).
En anglais on parle de phase ETL pour Extraction, Transformation and Loading 20.
La fréquence `a laquelle les phases ETL sont opérées doit ˆetre cohérente avec le grain de la dimension temporelle et doit permettre d’historiser les données avant qu’elles ne soient purgées des bases de production. Le remplissage initial des données à la création de l’entrepˆot est généralement facile. C’est historiser périodiquement et automatiquement les données qui pose problème.
En effet, les sources de données sont généralement multiples et gérées par différents systèmes (géographiquement
répartis dans différents sites), ce qui rend la phase ETL bien souvent très problématique.
Chaque situation rencontrée est très spécifique et l’architecture ETL mise en place est souvent dédiée à l’entreprise.
D’ailleurs le marché des outils ETL (qui sont très nombreux), est particulièrement morcelé. Il est
malgré tout dominé par :
* Informatica (PowerMart/Center)
* Ascential (DataStage)
* SAS (Warehouse Administrator).
Suivent les fournisseurs de SGBD :
* Oracle (Warehouse Builder)
* IBM (DataWarehouse Manager)
* Microsoft (DTS),
* Cognos et Hummingbird (parmi tant d’autres).
==== Data Transformation Services (DTS) ====
DTS est un outil fourni avec SQL Server. Il peut se connecter en lecture et en écriture :
* aux logiciels Microsoft, évidemment : SQL Server, Access, Excel et Visual FoxPro ;
* à d’autres SGBD : Corel Paradox, dBase, Oracle et mˆeme IBM DB2 ;
* à des fichiers textes ou des fichiers HTML.
DTS peut donc transférer les données non seulement d’une base SQL Server vers une base SQL Server, mais aussi d’une base DB2 vers une base Oracle, par exemple.
Cet outil permet non seulement de transférer les données, les nettoyer, les transformer, les fusionner et/ou les séparer. On entend par transformation tout calcul numérique ou toute opération sur chaˆines de caractères par exemple. Ces transformations peuvent ˆetre programmées dans des scripts SQL, Visual Basic, Java ou Perl et donc ˆetre extrˆemement complexes.
Une action DTS s’appelle un lot. Un lot DTS peut ˆetre exécuté régulièrement et automatiquement (en collaboration avec un autre service, SQL Server Agent, qui permet de planifier les opérations sur SQL
Server).
Un lot peut comporter plusieurs tˆaches que l’on peut enchaˆiner (sur succès ou sur échec de la tˆache
précédente) et dont on peut détecter et gérer les erreurs.
Pour nous, il s’agit d’utiliser DTS comme outil d’extraction périodique de données depuis les bases de
production vers la base décisionnelle. Parmi les tˆaches disponibles, nous intéressent plus particulièrement :
– les connexions aux données en lecture et en écriture ;
20. l’ETL fait partie des logiciels qui permettent aux applications hétérogènes de communiquer entre elle (middleware) au
mˆeme titre que l’EAI (Enterprise Application Integration) qui permet de maintenir `a jour les données entre les applications
en temps réel
* l’exécution de scripts paramétrés (essentiellement en SQL) ;
* l’exécution de sous-lots (ce qui permet de décomposer le lot ETL très complexe en lots extraction, transformation, chargement et traitement, plus simples) ;
* le traitement des cubes.
DTS offre également la possibilité d’utiliser des variables globales visibles par toutes les tˆaches. Pour
l’ETL, deux variables globales sont indispensables : la date de début et la date de fin qui délimite la
période de temps `a laquelle l’ETL s’applique. Typiquement, la date de début est la date de fin de la
précédente exécution du lot et la date de fin est la date courante.
Pour un approfondissement de cet outil, le lecteur est invité `a consulter [1] et [16].
17.2 Base tampon
étant donné qu’elles ont lieu pendant les plages horaires peu occupées (la nuit), l’ETL des données
OLTP pour le système OLAP entre en concurrence avec les sauvegardes des bases de production. Il faut
donc que cette phase perturbe le moins longtemps possible les systèmes OLTP. Pour cela, il faut que :
– l’extraction prenne le moins de temps possible ;
– les transformations n’aient pas lieu en mˆeme temps que l’extraction et pas sur le mˆeme serveur que
les systèmes OLTP;
Bref, les données extraites doivent atterrir sur une autre base, appelée base tampon (staging area).
Une fois l’étape d’extraction terminée, les transformations nécessaires. peuvent ˆetre effectuées tranquillement
dans la base tampon.
Il ne faut pas non plus que le système OLAP ne soit perturbé par la phase ETL (en particulier, par
l’étape de transformation). Autrement dit, cette base tampon ne doit pas ˆetre la base décisionnelle et
doit ˆetre gérée par un serveur dédié `a l’ETL (cf. figure 20).
Fig. 20 – Les étapes du processus ETL
17.3 étapes ETL
Détaillons maintenant les étapes de la figure 20.
=== Extraction ===
Pour que l’étape d’extraction dure le moins longtemps possible, il faut que :
– la requˆete de sélection ne comporte aucune jointure (il faut donc extraire les tables une par une) ;
– les données soient insérées dans des tables temporaires (elles n’ont aucune contrainte, aucun déclencheur
et aucun index).
Par ailleurs, il est bon que dans les systèmes OLTP, chaque table concernée par l’extraction (clients,
produits, etc.) soit munie d’une colonne pour la date de création et une autre pour la date de dernière
modification. Sans ces colonnes, on serait obligé d’extraire toutes les lignes et il serait compliqué de
déterminer (dans la base tampon) les lignes réellement modifiées depuis la dernière extraction. Avec ces
colonnes, l’extraction peut ˆetre incrémentale 21.
Dans tous les cas, le volume de données `a extraire est important. Il y a toujours un choix `a faire entre
extraire toutes les lignes d’un coup (la méthode la plus rapide, mais comme cette transaction est non
atomique, la moindre erreur est fatale `a tout le processus) ou les extraire une par une (ce qui prend plus
de temps, mais permet de limiter l’effet d’une erreur ponctuelle).
Exemple d’extraction :
1 SELECT *
2 INTO clients_temporaire1
3 FROM SERVEROLTP1.BaseProduction1.dbo.clients AS a
4 WHERE a.derniere_modification BETWEEN @debut AND @fin
5
6 SELECT *
7 INTO clients_temporaire2
8 FROM SERVEROLTP2.BaseProduction2.dbo.clients AS a
9 WHERE a.last_modification_date BETWEEN @debut AND @fin
10
11 SELECT *
12 INTO commandes_temporaire1
13 FROM SERVEROLTP1.BaseProduction1.dbo.commandes AS a
14 WHERE a.date BETWEEN @debut AND @fin
=== Transformation ===
Ce n’est pas parce que les données proviennent de bases de production qui fonctionnent rigoureusement
bien, que ces données sont valides pour le système décisionnel. Il faut presque toujours les transformer.
Les transformations se font en deux temps :
– d’abord, pendant le passage des données des tables temporaires aux tables tampon ;
– ensuite, des modifications sont apportées au sein des tables tampon en vue du chargement.
21. notons que l’extraction peut également ˆetre incrémentale si l’on utilise les informations contenues dans le journal des
transactions
17 ALIMENTATION DE L’ENTREP ˆOT 78
Tables tampon
`A
ce stade, la base tampon ne contient que des tables temporaires identiques aux tables source.
L’étape de transformation consiste `a consolider ces données dans les véritables tables de la base tampon
(cf. figure 21).
`A
chaque table de la base décisionnelle correspond une table tampon qui contient :
– les colonnes de la table de dimension ou de faits correspondante ;
– les clés naturelles et les clés de substitution ;
– une colonne exists de type oui ou non qui dira si le membre existe déj`a ou non ;
Ces tables tampon sont dépourvues de contraintes, notamment toutes ces colonnes autorisent la valeur
vide.
Fig. 21 – Tables temporaires et tables tampon
Remarques :
– pour faciliter le passage des tables temporaires aux tables tampon, il convient de supprimer, au
préalable, les index sur les tables tampon ;
– comme les bases de production sont multiples, il peut y avoir plusieurs tables temporaires qui
concerne les produits, par exemple ; donc l’insertion dans la table tampon qui concerne les produits
se fait en plusieurs fois ;
– la base tampon est totalement dépourvue de relation car on ne peut assurer ni l’intégrité des entités
ni l’intégrité référentielle, puisque les données source ne sont pas encore consolidées ;
– notons qu’il y a souvent un travail de jointure `a faire sur les tables temporaires pour insérer les
données dans les tables tampon ;
– notons enfin que si le grain des bases de production est plus fin que celui de la base décisionnelle,
les premières agrégations nécessaires peuvent ˆetre effectuées `a ce moment-l`a.
Réparation, complétion, synchronisation et formattage
Pendant que les données sont insérées dans les tables tampon, on peut les uniformiser, c’est-`a-dire les
réparer, les compléter, les synchroniser et les formatter.
Exemple de réparation des données : les codes postaux invalides peuvent ˆetre corrigés en utilisant un
annuaire des codes postaux.
Exemple de complétion des données : déduire la région o`u est domicilié un propriétaire `a partir du
numéro d’immatriculation de son véhicule.
Rappelons que les bases de production n’utilisent pas forcément la mˆeme horloge. Il faut donc synchroniser
toutes les dates contenues dans les tables temporaires pendant leur transfert dans les tables tampon.
Par ailleurs, quand les données arrivent dans la base tampon, elles ne sont pas toutes au mˆeme format
et ne respectent pas forcément le format de la base décisionnelle (généralement, les contraintes sur les
chaˆines de caractères ne sont pas les mˆemes dans toutes les bases et les codages de date sont hétérogènes).
Il faut donc uniformiser les formats avant le chargement, c’est le formattage.
Exemple d’hétérogénéité : selon leur provenance, les noms de clients peuvent arriver sous la forme
de deux colonnes (nom et prenom) ou sous la forme d’une colonne (nom + prenom, nom + initiale +
prenom). Un autre exemple classique concerne les adresses : il y a quasiment autant de formats que de
bases.
Exemple d’insertion dans une table tampon `a partir d’une table temporaire :
1 INSERT clients_tampon
2 (cle_naturelle, source, NomPrenom, ville, region, pays, date_creation)
3 SELECT a.clt_num, ’SERVEROLTP1.BaseProduction1’, -- pour la substitution
4 a.nom + ’ ’ + a.prenom, -- formattage
5 b.ville, b.region, a.pays, -- completion
6 DATEADD(hour, -3, a.date_creation) -- synchronisation
7 FROM clients_temporaire1 AS a
8 JOIN CodesPostaux AS b ON (a.CodePostal = b.CodePostal)
Notons qu’un client peut ˆetre inséré en double dans sa table tampon, s’il figure dans deux bases de
production. Les doublons sont gérés par le paragraphe suivant. De plus, deux clients différents mais qui
portent la mˆeme clé naturelle, sont distinguables par leur source (et leurs attributs).
Substitution des clés primaires
Une fois que les tables tampons sont remplies, on peut supprimer les tables temporaires et s’occuper
de l’intégrité des données qui vont ˆetre chargées dans la base décisionnelle. Pour rendre la substitution, la
validation et le chargement le plus rapide possible, il convient de re-créer les index sur les tables tampons.
Rappelons que la base décisionnelle n’utilise pas les clés naturelles des bases de production car :
– un produit peut ˆetre identifié dans deux bases de production différentes avec des clés distinctes ;
– un numéro de produit peut correspondre `a deux produits distincts dans deux bases de production
différentes.
Au contraire, pour identifier les membres de manière unique, la base décisionnelle utilise des clés de
substitution (surrogate keys).
Au cours de l’étape de transformation, il faut donc traduire (lookup) les clés naturelles en clés de
substitution et remplir la colonne exists. Si les bases de production ne sont pas pourvues d’une colonne
pour la date de création et une colonne pour la date de dernière modification, alors cette traduction implique
la recherche du membre correspondant (en fonction de leurs attributs dans la base décisionnelle)
pour chaque ligne extraite. Non seulement c’est très coˆuteux mais en plus, cela perturbe le système OLAP.
Exemple de lookup pour les clés primaires de substitution :
1 -- recherche des membres deja presents
2 UPDATE clients_tampon
3 SET exists = 1, cle_substitution = b.cle
4 FROM clients_tampon AS a
5 JOIN SERVEROLAP.BaseDecisionnelle.dbo.clients_dimension AS b ON
6 (
7 ISNULL(a.NomPrenom, ’’) = ISNULL(b.NomPrenom, ’’) AND
8 ISNULL(a.pays, ’’) = ISNULL(b.pays, ’’) AND
9 ISNULL(a.region, ’’) = ISNULL(b.region, ’’) AND
10 ISNULL(a.ville, ’’) = ISNULL(b.ville, ’’)
11 ) -- pays et region sont utiles pour distinguer les villes homonymes
12
13 -- nouvelle cle pour les nouveaux membres
14 UPDATE clients_tampon
15 SET cle_substitution = NEWID()
16 WHERE exists IS NULL
Notons que les clients insérés en double dans la table clients tampon, possèdent désormais une clé
de substitution unique (sauf les nouveaux membres) et que les clients distincts mais avec la mˆeme clé
primaire, possèdent désormais deux clés de substitution distinctes.
Dérive dimensionnelle
Notons aussi, que si un client change de ville, il faut faire un choix entre :
– changer la ville de ce membre (et donc changer les agrégats de cette ville), ce qui n’est pas recommand
é ;
– ou insérer un nouveau membre pour ce client et sa nouvelle ville (c’est le cas dans l’exemple
précédent).
On peut en venir `a introduire un numéro de version `a chaque membre et une date de création pour
chaque version. La clé primaire de la table de dimension est alors composée de deux colonnes : la clé de
substitution et le numéro de version. C¸ a n’est pas la solution que nous avons retenue ici.
Substitution des clés étrangères
Il reste encore `a traiter l’intégrité référentielle des données qui vont ˆetre chargées dans la base
décisionnelle. Pour cela, il faut recalculer les clés étrangères avec les clés de substitution afin que les
relations de la base décisionnelle soient vérifiées lors du chargement (cf. figure 22).
Fig. 22 – ´ Evolution des tables clients et commandes au cours du processus ETL
Malheureusement, certaines clés étrangères peuvent ˆetre introuvables. Dans toutes les tables de dimension,
il faut donc prévoir un membre 0 qui permet de traiter ces relations invalides 22. Ce membre 0
est créé une bonne fois pour toutes dans chaque table de dimension de la base décisionnelle :
1 -- sur le server OLAP et dans la base decisionnelle
2 INSERT clients_dimension (cle, NomPrenom, pays, region, ville)
3 VALUES (0, ’autre’, ’autre’, ’autre’, ’autre’)
22. la numérotation des membres valides doit donc commencer `a 1
17 ALIMENTATION DE L’ENTREP ˆOT 82
Exemple de lookup pour les clés étrangères de substitution (dans la base tampon) :
1 -- traitement des relations valides
2 UPDATE commandes_tampon
3 SET client_cle_substitution = b.cle_substitution
4 FROM commandes_tampon AS a
5 JOIN clients_tampon AS b ON
6 (
7 a.cmd_clt = b.clt_num AND
8 a.source = b.source
9 )
10
11 -- traitement des relations invalides
12 UPDATE commandes_tampon
13 SET client_cle_substitution = 0
14 WHERE client_cle_substitution IS NULL
Remarque : la phase de substitution est plus simple pour un schéma en étoile que pour un schéma en
flocon. Il faut en tenir compte lors de la conception de la base décisionnelle.
=== Chargement ===
Comme les données sont chargées dans la base décisionnelle qui est muni d’un schéma relationnel, il faut charger ses tables dans cet ordre :
- d’abord les tables qui ne contiennent aucune clé étrangère ;
– ensuite les tables qui ne contiennent que des clés étrangères vers des tables déj`a chargées ;
– etc.
Ensuite, pour chaque table, le chargement de décompose en deux requˆetes :
– une pour les nouveaux membres ou faits ;
– et une pour les membres ou faits modifiés.
Exemple de chargement dans une table de dimension :
<code>
1 -- chargement des nouveaux membres
2 INSERT SERVEROLAP.BaseDecisionnelle.dbo.clients_dimension
3 SELECT cle_substitution, NomPrenom, ville, region, pays, age, profession
4 FROM clients_tampon
5 WHERE exists IS NULL
6
7 -- modification des anciens membres
8 UPDATE SERVEROLAP.BaseDecisionnelle.dbo.clients_dimension
9 SET age = a.age,
10 profession = a.profession
11 FROM clients_tampon AS a
12 JOIN SERVEROLAP.BaseDecisionnelle.dbo.clients_dimension AS b
13 ON (a.cle_substitution = b.cle)
14 WHERE a.exists = 1
</code>
Exemple de chargement dans une table des faits :
<code>
1 -- chargement des nouveaux faits
2 INSERT SERVEROLAP.BaseDecisionnelle.dbo.commandes_faits
3 SELECT cle_substitution, client_cle_substitution, date
4 FROM commandes_tampon
5 WHERE exists IS NULL
6
7 -- modification des anciens membres
8 UPDATE SERVEROLAP.BaseDecisionnelle.dbo.commandes_faits
9 SET client_cle_substitution = a.client_cle_substitution
10 date = a.date
11 FROM commandes_tampon AS a
12 JOIN SERVEROLAP.BaseDecisionnelle.dbo.commandes_faits AS b
13 ON (a.cle_substitution = b.cle)
14 WHERE a.exists = 1
</code>
=== Traitement ===
Le traitement des cubes intervient juste derrière la phase ETL proprement dite. Il d’agit d’une opération entièrement réalisée par Analysis Services, mais il s’agit d’une tˆache que l’on peut inclure dans le même lot DTS que l’ETL.
Hormis pour le remplissage initial de l’entrepˆot, le traitement des cubes doit ˆetre incrémental. Pour cela, il est conseillé de partitionner le cube avec notamment une partition séparée pour l’année en cours, afin de ne pas traiter les autres années (qui, normalement, ne sont pas touchées par les modifications).
Structurer les données en cube
On sent bien que la table est un objet bidimensionnel mal adapté `a l’agrégation de données dès que le
groupement porte sur deux colonnes ou plus. L’état offre une première solution, mais la feuille A4 (mˆeme
orientée en paysage) est rapidement saturée quand le nombre de niveau de groupement augmente et la
navigation dans un état de 200 pages est fastidieuse.
==== Définition d’un cube ====
On préférerait donc un objet :
– qui aurait autant de dimensions qu’il y a de colonnes de groupement (clients et pays dans notre
exemple précédent) ;
– dont chaque dimension détaillerait les valeurs possibles (France et Italie pour la dimension pays) ;
– dans lequel, `a l’intersection d’une valeur dans chaque dimension (France et 0001 par exemple) on
trouverait une unique cellule ;
– une cellule qui contiendrait toutes les valeurs agrégées pour ce sous-groupe (c’est-`a-dire les mesures
tel que le nombre de commandes et le montant total) ;
– et aussi les agrégats des ces valeurs pour les sous-groupes supérieurs.
C’est cet objet que l’on appelle cube.
Par exemple, organisons, en cube, les données de la requˆete suivante :
1 SELECT a.cmd_clt, b.btq_pays, COUNT(cmd_num), SUM(cmd_montant)
2 FROM commandes AS a
3 JOIN boutiques AS b ON a.cmd_btq = b.btq_num
4 GROUP BY a.cmd_clt, b.btq_pays WITH CUBE
Résultat :
Fig. 11 – Cube bidimensionnel
Remarque : le terme de cube ne présupposant ni du nombre de dimensions ni de l’égalité des longueurs
des dimensions (cf. figure 11).
En MDX, pour créer ce cube il suffit d’écrire :
1 CREATE CUBE ClientsPays
2 (
3 DIMENSION clients
4 DIMENSION pays
5 MEASURE NbCommandes FUNCTION COUNT
6 MEASURE [Montant total] FUNCTION SUM
7 )
Remarque : on dispose bien évidemment de DROP CUBE et de ALTER CUBE18.
Mesures
Les mesures sont généralement additives (soit une somme, soit un dénombrement).
Il ne faut stocker dans le cube que les mesures primitives :
– le prix TTC peut ˆetre calculé `a partir du prix hors taxe, ce n’est donc pas la peine de le stocker ;
– il en va de mˆeme pour les prix en dollars `a partir des prix en euros ;
18. on laisse au lecteur le soin de se renseigner auprès de l’aide en ligne pour connaˆitre les possibilités de ALTER CUBE
15 STRUCTURER LES DONNéES EN CUBE 65
– d’un montant `a partir d’un prix unitaire et d’une quantité ;
– etc.
Dans Analysis Services, les mesures non primitives peuvent ˆetre calculées avec les membres calculés
(cf. §18.4.1 page 91).
Ceci dit, si les règles de calcul des mesures non primitives sont compliquées ou si elles changent souvent
(c’est le cas des conversions euro/dollar, par exemple), alors il vaut mieux stocker une mesure de plus.
15.2 Hiérarchie
Complexifions progressivement la définition d’un cube.
15.2.1 Niveaux
Avec la structure de cube, on peut détailler chaque dimension en plusieurs niveaux. Par exemple,
une dimension générale geographie peut permettre des groupements selon un pays, une region ou une
ville. On voit alors apparaˆitre une hiérarchie dans les dimensions que l’on dépliera et pliera `a volonté,
selon nos besoins d’agrégation.
On peut prendre comme illustration un cube ventes `a trois dimensions (cf. figure 12) :
– une dimension geographie comprenant plusieurs pays qui se décomposent chacun en plusieurs
régions qui regroupent elles-mˆemes plusieurs villes dans lesquelles se situent les boutiques ;
– une dimension produits dans laquelle les articles sont regroupés en gammes puis en marques ;
– et une dimension temporelle détaillée en années, mois et jours.
Fig. 12 – Cube ventes hiérarchisé
La syntaxe MDX pour déclarer ces dimensions hiérarchisées est
– pour les dimensions standards :
1 DIMENSION geographie
2 LEVEL tout TYPE ALL, -- mettre ce niveau a chaque fois
3 LEVEL pays,
4 LEVEL region,
5 LEVEL ville
6
7 -- on separe les niveaux par des virgules mais pas les dimensions
8
9 DIMENSION produits
10 LEVEL tout TYPE ALL, -- du plus agrege
11 LEVEL marque,
12 LEVEL gamme,
13 LEVEL article -- au plus detaille
– et pour la dimension temporelle :
1 DIMENSION temps
2 LEVEL tout TYPE ALL,
3 LEVEL annee TYPE YEAR,
4 LEVEL mois TYPE MONTH,
5 LEVEL jour TYPE DAY
Remarques :
– le niveau ALL un niveau formel qui regroupe tous les autres ;
– s’il y a ambigu¨ité sur le nom des niveaux, il suffit de préciser la dimension concernée selon la
syntaxe : dimension.niveau (exemple : produits.articles) ;
– dans une dimension hiérarchisée, les données du niveau le plus bas sont issues des bases de production
;
– mais le cube peut aussi stocker des données aux niveaux supérieurs (il s’agit le plus souvent de
données agrégées, mais pas toujours).
Le niveau le plus bas d’une dimension s’appelle le grain de la dimension (le grain de la dimension
geographie c’est la ville). Toutes les dimensions et leur grain doivent ˆetre choisis dès le début et doit
rester inchangés pendant toute la durée de vie du cube.
15.2.2 Membres
Les différentes valeurs d’un niveau sont appelées membres. Par exemple, les membres du niveau pays
sont France, Italie, Allemagne et Espagne. Un membre de niveau supérieur regroupe des membres du
niveau immédiatement inférieur, ce sont ses enfants. Par exemple, les enfants du membre France sont
PACA, Rhones-Alpes et Corse.
Remarque : un membre d’un niveau supérieur (une région) peut posséder des données (son ensoleillement,
par exemple) et pas seulement des agrégats (montant total des ventes dans cette région).
15 STRUCTURER LES DONNéES EN CUBE 67
15.2.3 Hiérarchies multiples
Certaines dimensions peuvent ˆetre organisées selon plusieurs hiérarchies.
C’est classiquement le cas de la dimension temporelle qui peut non seulement ˆetre organisée en :
– jours, mois, trimestres et années ;
– mais aussi en jours et semaines ;
– ou encore en jours et saisons.
Cela peut également se produire pour n’importe quelle dimension (cf. la dimension produits sur la figure
16).
Analysis Services ne permet malheureusement pas `a une dimension de posséder plusieurs hiérarchies.
La technique pour les représenter malgré tout consiste alors simplement :
– soit `a introduire plusieurs dimensions (avec une hiérarchie chacune), ce qui n’est pas recommandé ;
– soit `a utiliser les propriétés de membre (cf. §19.1 page 96) et les dimensions virtuelles.
15.3 Normalisation d’un cube
Le schéma relationnel d’un cube (cf. section suivante) n’a pas besoin de respecter la troisième forme
normale (cf. [?]), ce qui permet d’utiliser des schémas en étoile. Par contre, quelques règles (tirées de [4])
doivent ˆetre respectées lors de la construction de chaque cube :
Règle 1 : dans un cube, deux membres appartenant `a deux dimensions différentes doivent ˆetre
indépendants .
Autrement dit, s’il n’y a qu’un vendeur par produit, il faut fusionner les dimensions produits et
vendeurs.
Règle 2 : dans un cube, tous les faits doivent dépendent de toutes les dimensions.
Autrement dit, les ventes (qui dépendent du produit, du jour, du client et de la ville) et les coˆuts de
développement (qui ne dépendent que du produit) définissent deux types de faits distincts (et conduisent
donc `a deux cubes distincts).
Règle 3 : dans un cube, toutes les mesures doivent respecter le grain du cube.
Si la marge n’est définie que par région et par mois, tandis que le montant des ventes le sont par
ville et par jour, alors il ne faut pas chercher `a les faire cohabiter par une division arithmétique mais les
séparer dans deux cubes distincts.
Règle 4 : la hiérarchie d’une dimension doit ˆetre strictement arborescente.
Ce n’est pas le cas d’une dimension organisation dans laquelle :
– les agences sont regroupées administrativement en divisions ;
– les agences sont regroupées géographiquement en établissements, mˆeme si elles appartiennent `a des
divisions différentes ;
– les divisions sont regroupées en directions régionales ;
– les établissement sont également regroupés en directions régionales.
Il faut alors utiliser deux hiérarchies pour cette dimension :
– une dont les niveaux sont : agences, divisions et directions régionales ;
– et une autre dont les niveaux sont : agences, établissement et directions régionales .
Lorsqu’un cube vérifie ces quatres règles, on dit qu’il est en forme dimensionnelle normale.
===== Interroger un cube =====
Avant de découvrir comment consulter un cube, définissons quelques opération de navigation dans
un cube :
– le dépliage (drilldown) qui consiste `a passer `a un niveau inférieur dans une dimension ;
– le pliage (drillup ou rollup) qui consiste `a passer `a un niveau supérieur dans une dimension ;
– le tranchage ou découpage (slice) qui consiste `a ne garder qu’une tranche du cube (une tranche
étant une coupe du cube selon un membre) ;
– le cubage (dice) qui s’intéresse `a plusieurs tranches `a la fois ;
– et la rotation qui consiste `a choisir les dimensions que l’on veut en colonnes et en lignes.
Avec ces cinq opérations, on peut naviguer dans les données (i.e. pratiquer le data surfing). Il faut
y ajouter une sixième opération : le drillthrough (traduit maladroitement par extraction dans Analysis
Services, le terme de désagrégration étant préférable) qui permet de retrouver les données qui ont permis
de calculer un agrégat.
18.1 Requˆetes MDX
La syntaxe pour rédiger une requˆete MDX est la suivante :
WITH certaines notations
SELECT les colonnes, les lignes et les autres axes
FROM le cube
WHERE les dimensions tranchées et leur tranche (au singulier)
CELL PROPERTIES les informations contextuelles voulues pour les cellules
Le résultat d’une telle requˆete est un tableau multidimensionnel dont les cellules ne contiennent
qu’une valeur (contrairement aux cubes) et dans lequel on peut naviguer avec les opérations décrites
précédemment.
Parmi les dimensions du cube initial, certaines servent d’axes (un axe contient les membres issus d’un
dépliage et/ou d’un cubage) pour le résultat (clause SELECT) et d’autres de tranchage (clause WHERE)
mais pas les deux `a la fois.
Pour MDX, les mesures constituent une dimension, et peuvent donc faire l’objet d’un axe ou d’un
tranchage.
Affichons par exemple, le montant des ventes, avec en colonne l’année 2002 et en ligne la région PACA :
<code>
1 SELECT {temps.annee.[2002]} ON COLUMNS,
2 {geographie.region.PACA} ON ROWS
3 FROM ventes
4 WHERE (measures.montant)
</code>
Le résultat de cette requˆete est le suivant :
2002
PACA 56986.12
Remarques :
– n’oublier ni les accolades dans la clause SELECT ni les parenthèses dans la clause WHERE ;
– rappel : dès qu’un intitulé contient une espace, un accent ou commence par un chiffre, il faut le
délimiter par des crochets ;
– si l’intitulé utilise un crochet fermant ], employer les doubles crochets fermants :
Bill [William]] Clinton]
– pour des raisons qui deviendront claires au §18.4.2 page 93, si l’intitulé contient une quote ’, alors
il faut la doubler :
[k’’s Choice]
– la syntaxe complète des noms de membres dans un cube est :
dimension . niveau . membre
– s’il n’y a pas de confusion possible on peut omettre la dimension et/ou le niveau ;
– si dans un mˆeme niveau plusieurs membres ont le mˆeme nom, préciser autant de parents que
nécessaire pour les distinguer :
dimension . [ancˆetre le plus ancien] ... [grand-père] . [père] . membre
18.1.1 Clause SELECT
La clause SELECT offre plusieurs possibilités. On peut afficher :
– plusieurs colonnes et plusieurs lignes :
1 SELECT {temps.annee.[1998], temps.annee.[2002]} ON COLUMNS,
2 {geographie.region.PACA, geographie.pays.France} ON ROWS
3 FROM ventes
4 WHERE (measures.montant)
Résultat : 2 colonnes et 2 lignes
1998 2002
PACA 133419.96 56986.12
France 1458311.45 248996.54
– tous les enfants d’un membre :
1 SELECT temps.annee.[1998].CHILDREN ON COLUMNS,
2 {geographie.region.PACA} ON ROWS
3 FROM ventes
4 WHERE (measures.montant)
Résultat : autant de colonnes qu’il y a d’enfants
Janvier Février Mars Avril ... Octobre Novembre Décembre
PACA 19856.45 11458.58 7589.47 8799.15 ... 11589.45 10569.65 38360.35
– tous les membres d’un niveau :
1 SELECT temps.annee.MEMBERS ON COLUMNS,
2 {geographie.region.PACA} ON ROWS
3 FROM ventes
4 WHERE (measures.montant)
Résultat : autant de colonnes qu’il y a de membres
1998 1999 2000 2001 2002
PACA 133419.96 121598.45 104789.56 89634.25 56986.12
– une plage de membres :
1 SELECT {temps.annee.[1998] : temps.annee.[2001]} ON COLUMNS,
2 {geographie.region.PACA} ON ROWS
3 FROM ventes
4 WHERE (measures.montant)
Résultat : autant de colonnes que d’années entre 1998 et 2001 (inclus)
1998 1999 2000 2001
PACA 133419.96 121598.45 104789.56 89634.25
18 INTERROGER UN CUBE 86
Remarques :
– il n’y a pas de confusion possible entre MEMBERS et CHILDREN puisque l’un s’applique `a un niveau,
l’autre `a un membre :
dimension . niveau . MEMBERS
dimension . niveau . membre . CHILDREN
– on peut aussi utiliser :
dimension . MEMBERS (les membres de tous les niveaux de la dimension)
dimension . CHILDREN (les membres du niveau le plus élevé)
– avant d’utiliser l’opérateur :, s’assurer de l’ordre dans lequel sont stockés les membres.
18.1.2 Mesures
On peut afficher plusieurs mesures `a la fois. Mais comme le résultat d’une requˆete n’autorise qu’une
valeur par cellule, il faut aligner les mesures selon un axe :
1 SELECT temps.annee.MEMBERS ON COLUMNS,
2 {measures.montant, measures.NbCommandes} ON ROWS
3 FROM ventes
Résultat : sur tous les articles et dans tous les pays
1998 1999 2000 2001 2002
montant 1133419.96 1121598.45 1104789.56 189634.25 156986.12
nb 2569 2107 1568 1474 978
Les mesures forment donc naturellement une dimension nommée measures dans chaque cube. On
précise quelle mesure afficher dans la clause WHERE quand on en veut qu’une (c’est une tranche du cube).
Et on est obligé d’en préciser au moins une, sans quoi une mesure est choisie par défaut.
18.1.3 Clause WHERE
On peut effectuer plusieurs découpes sur le cube. Reprenons par exemple la requˆete précédente :
1 SELECT temps.annee.MEMBERS ON COLUMNS,
2 {measures.montant, measures.NbCommandes} ON ROWS
3 FROM ventes
4 WHERE (produits.marque.Channel, geographie.pays.Italie)
Résultat : sur tous les articles de la marque Channel et pour l’Italie seulement
1998 1999 2000 2001 2002
montant 419.96 598.45 789.56 634.25 986.12
nb 69 107 68 74 78
Remarques :
– une dimension ne peut apparaˆitre qu’une fois dans la clause WHERE ;
– si on veut plusieurs tranches dans une dimension, il faut en faire un axe ;
– on ne peut utiliser dans la clause WHERE ni MEMBERS ni CHILDREN.
Le grand danger relatif aux découpes de cube, est que certaines applications MDX n’affichent pas les
tranches alors que c’est une information indispensable pour comprendre les valeurs des mesures.
18.1.4 Description des axes
Une requˆete MDX autorise jusqu’`a 127 axes, mais évidemment on ne peut pas dépasser le nombre
de dimensions du cube +1 (avec la dimension measures). Les cinq premiers axes sont : COLUMNS, ROWS,
PAGES, SECTIONS et CHAPTERS. Au-del`a il faut utiliser : AXIS(5), ..., AXIS(126).
Exemple `a quatre dimensions :
1 SELECT temps.annee.MEMBERS ON COLUMNS,
2 geographie.pays.MEMBERS ON ROWS,
3 produits.article.MEMBERS ON PAGES,
4 {measures.montant, measures.NbCommandes} ON SECTIONS
5 FROM ventes
On peut aussi créer un résultat ayant un seul axe :
1 SELECT temps.annee.MEMBERS ON COLUMNS
2 FROM ventes
3 WHERE (measures.montant)
Résultat : les intitulés de colonne et une seule ligne de résultats (pas d’intitulé de ligne)
1998 1999 2000 2001 2002
1133419.96 1121598.45 1104789.56 189634.25 156986.12
Ou mˆeme n’ayant aucun axe :
1 SELECT
2 FROM ventes
3 WHERE (measures.montant)
Résultat : une cellule contenant le montant total des ventes de toutes les années pour tous les produits
et partout (c’est un mauvais exemple)
3706428.34
18.1.5 MDX vs. SQL
Comme on vient de le voir, les requˆetes MDX ressemblent beaucoup aux requˆetes SQL de sélection.
Ceci dit, notons quand mˆeme des différences fondamentales :
– la syntaxe des clauses SELECT et WHERE n’a rien `a voir ;
– la clause FROM n’admet qu’un seul cube, en MDX;
– les clauses SQL GROUP BY, HAVING et ORDER BY n’existent pas en MDX;
– et il existe d’autres clauses spécifiques `a MDX (WITH et CELL PROPERTIES).
18 INTERROGER UN CUBE 88
18.2 Filtrage des données
Jusqu’`a maintenant, la clause SELECT n’a servi qu’`a sélectionner les membres que l’on peut désigner.
Si on veut faire intervenir un critère plus complexe, comme : ne garder que les membres dont une mesure
est dans une certaine plage, alors il faut utiliser la fonction MDX :
FILTER(les membres `a filter, (le critère))
Par exemple, pour n’afficher que les années pour lesquelles on a vendu pour plus de 100000 :
1 SELECT FILTER(temps.annee.MEMBERS, (measures.montant > 113000)) ON COLUMNS
2 FROM ventes
3 WHERE (measures.montant)
Résultat : il ne reste que les années concernées par le critère
1998 2001 2002
1133419.96 189634.25 156986.12
Remarques :
– la mesure dans la clause WHERE n’est pas obligatoirement la mˆeme que celle utilisée dans le filtre ;
– le critère peut faire appel aux fonctions MDX (cf. aide en ligne).
Exemple : pour ne garder que les pays qui ont vendu plus que la France, l’Italie et l’Allemagne
1 SELECT FILTER(geographie.pays.MEMBERS, (measures.montant >
2 MAX({France, Italie, Allemagne}, measures.montant) -- ici
3 )) ON COLUMNS
4 FROM ventes
5 WHERE (measures.montant)
Remarque : MDX offre toutes les fonctions d’agrégat (mais avec deux arguments) ainsi que MEDIAN.
Si le critère ne porte pas directement sur les agrégats des membres `a filtrer mais sur des valeurs plus
fines, alors il faut faire appel `a la notion de tuple pour décrire ces valeurs. Le tuple est la généralisation
de la notion de couple et de triplet, il correspond aux coordonnées des valeurs voulues dans le cube.
Exemple de tuple : le montant des ventes pour le mois de janvier 2002 se note par le couple :
([2002].janvier, measures.montant)
Autre exemple : le nombre de commandes du client Razibus en France et en 1999 se note par le
quadruplet :
(clients.Razibus, geographie.France, temps.[1999], measures.NbCommandes)
Remarques :
– l’ordre a parfois de l’importance dans un tuple ;
– les composantes d’un tuple doivent ˆetre issues de dimensions différentes.
Avec cette notation, on peut par exemple filtrer les articles pour lesquels les ventes ont augmenté
entre janvier 2001 et janvier 2002 :
1 SELECT FILTER(produits.article.MEMBERS,
2 (([2001].janvier, measures.montant) < ([2002].janvier, measures.montant))
3 ) ON COLUMNS
4 FROM ventes
5 WHERE (measures.NbCommandes) -- on n’est pas oblige d’afficher le montant
Remarque : les membres `a filtrer peuvent ˆetre définis en plusieurs fois. Par exemple, pour filtrer les
mois de 2001 et de 2002 pendant lesquels il a été vendu pour un montant supérieur `a 10 000 :
1 SELECT FILTER({[2001].CHILDREN, [2002].CHILDREN},
2 (measures.montant > 10000)) ON COLUMNS
3 ...
Remarque : on peut afficher les deux montants utilisés dans le filtre
1 SELECT FILTER(produits.article.MEMBERS,
2 (([2001].janvier, measures.montant) < ([2002].janvier, measures.montant))
3 ) ON COLUMNS,
4 {([2001].janvier, measures.montant), ([2002].janvier, measures.montant)}
5 ON ROWS
6 FROM ventes
Compléments
Sans utiliser la fonction FILTER, on peut éliminer simplement les membres qui ne contiennent pas de
données :
SELECT NON EMPTY {...} ON COLUMNS
Par ailleurs, on peut ne garder que les membres extremaux avec la fonction :
TOPCOUNT(les membres `a filtrer, le nombre voulu, (la mesure pour établir le classement))
Filtrons par exemple les 10 articles les plus vendus :
1 SELECT TOPCOUNT(article.MEMBERS, 10, (measures.NbCommandes))
2 ON COLUMNS
3 ...
Remarques :
– l`a aussi, on peut décrire les membres `a filtrer en plusieurs fois (en utilisant des accolades) ;
– l`a aussi, on peut employer un tuple en troisième argument ; exemple : les 10 articles les plus vendus
en 1998 :
1 SELECT TOPCOUNT(article.MEMBERS, 10, (measures.NbCommandes, [1998]))
2 ON COLUMNS
3 ...
– on a évidemment la fonction BOTTOMCOUNT (mˆeme syntaxe) ;
– il existe aussi TOPSUM et TOPPERCENT (cf. l’aide en ligne).
18 INTERROGER UN CUBE 90
18.3 Disposition des résultats
On peut encore rendre les requˆetesMDX plus complexe lorsque l’on chercher `a réorganiser les résultats.
18.3.1 Ordonner les axes
Pour ordonner les membres dans un axe et selon une mesure (et non pas par ordre alphabétique), on
utilise dans la clause SELECT la fonction :
ORDER(les membres `a trier, (la mesure selon laquelle trier), ASC ou DESC)
Exemple, pour ordonner les années de la plus lucrative `a la moins lucrative :
1 SELECT ORDER(annee.MEMBERS, (measures.montant), DESC) ON COLUMNS
2 ...
Remarques :
– on peut faire appel aux tuples pour désigner le critère de tri ; exemple, les années de la plus lucrative
`a la moins lucrative en France :
1 SELECT ORDER(annee.MEMBERS, (measures.montant, pays.France), DESC) ON COLUMNS
2 ...
– `a nouveau, on peut décrire les membres `a trier en plusieurs fois (en utilisant des accolades). Par
exemple, trions les mois de 2000 et de 2001 selon le montant des ventes de pinceaux :
1 SELECT ORDER({[2000].CHILDREN, [2001].CHILDREN},
2 (produits.pinceau, measures.montant), ASC) ON COLUMNS
3 ...
Mais le problème avec ASC et DESC est que la hiérarchie est respectée (dans notre exemple, les mois
de 2000 seront triés séparemment des mois de 2001). Pour ne pas tenir compte de la hiérarchie, il suffit
d’utiliser BASC et BDESC.
18.3.2 Axes pluridimensionnels
On a parfois besoin que le résultat ne comporte que deux axes (ne serait-ce que pour l’imprimer),
sans pour autant perdre la possibilité d’utiliser 3 dimensions ou plus dans la clause SELECT. La solution
consiste `a représenter plusieurs dimensions par axe. Pour cela, on utilise les tuples.
Exemple, présentons `a la fois les années et les pays en colonne :
1 SELECT {(France,[2000]), (France,[2001]),
2 (Italie,[2000]), (Italie,[2001])} ON COLUMNS
3 ...
Résultat : certains intitulés sont multicolonnes
France Italie
2000 2001 2000 2001
18 INTERROGER UN CUBE 91
Remarques :
– dans ce cas, l’ordre `a l’intérieur de chaque tuple a de l’importance ;
– les tuples doivent ˆetre homogènes (c’est-`a-dire présenter les mˆemes dimensions et dans le mˆeme
ordre).
Si on veut ensuite détaillé chaque année selon les produits A, B et C, on voit tout de suite que la clause
SELECT serait longue `a écrire (12 triplets). Heureusement, on peut générer les tuples par produit cartésien :
1 SELECT CROSSJOIN({France, Italie}, {[2000], [2001]}) ON COLUMNS
2 ...
3 -- donne la meme chose que precedemment
4
5 SELECT CROSSJOIN(CROSSJOIN({France, Italie}, {[2000], [2001]}),
6 {A, B, C}) ON COLUMNS
7 ...
Résultat : trois dimensions sur l’axe des colonnes
France Italie
2000 2001 2000 2001
A B C A B C A B C A B C
18.4 Clause WITH
Comme on l’a déj`a vu, les requˆetes MDX présentent une dernière clause, la clause WITH qui offre la
possibilité de définir certains objets avant le début du SELECT.
Les objets définis dans une clause WITH ne sont visibles que dans la clause SELECT qui suit. C’est
pourquoi Analysis Services propose également de les définir dans l’éditeur de cube afin qu’ils soient utilisables
par toutes les requˆetes.
Comme la syntaxe est la mˆeme, nous nous contentons ici d’utiliser la clause WITH.
18.4.1 Membres calculés
Un membre calculé est un membre supplémentaire dont la définition repose sur les membres déj`a
présents dans le cube. Il s’agit d’un calcul entre membres dont le résultat peut ˆetre utilisé comme un
membre `a part entière.
Exemple : `a partir des membres juillet 2001 et juillet 2002, on peut définir un membre calculé
qui représente la progression entre juillet 2001 et juillet 2002 ainsi :
1 WITH MEMBER temps.[de juillet 2001 a juillet 2002] -- le nom complet
2 AS ’temps.[2002].juillet - temps.[2001].juillet’ -- l’expression du calcul
3 SELECT {temps.[2001].juillet, temps.[2002].juillet
4 temps.[de juillet 2001 a juillet 2002]} ON COLUMNS
5 FROM ventes
6 WHERE (measures.montant)
18 INTERROGER UN CUBE 92
Résultat : la troisième colonne présente la progression du chiffre d’affaire entre juillet 2001 et juillet
2002
juillet 2001 juillet 2002 de juillet 2001 a juillet 2002
10186.12 9486.78 -699.35
Jusqu’ici on s’est contenté d’utiliser les mesures brutes (tel qu’elles sont stockées dans le cube). Si
on veut afficher des mesures plus complexes, il suffit de définir un membre calculé en fonction d’autres
mesures.
Si, par exemple, on dispose des mesures montant et quantite alors on peut définir le membre calculé
prix unitaire :
1 WITH MEMBER measures.prix_unitaire -- le nom complet
2 AS ’measures.montant / measures.quantite’ -- l’expression du calcul
3 SELECT article.MEMBERS ON COLUMNS
4 FROM ventes
5 WHERE (measures.prix_unitaire)
Les membres calculés ne sont pas retournés par défaut par la fonction MEMBERS, il faut utiliser la fonction
ADDCALCULATEDMEMBERS. Si on veut voir apparaˆitre le nouvelle mesure prix unitaire par exemple :
1 WITH MEMBER measures.prix_unitaire
2 AS ’measures.montant / measures.nb’
3 SELECT ADDCALCULATEDMEMBERS(measures.MEMBERS) ON COLUMNS
4 FROM ventes
5 WHERE (temps.[2001])
Remarques :
– les valeurs des membres calculés ne sont pas stockées dans le cube, mais calculées `a la volée (ce qui
ralentit raisonnablement les requˆetes) ;
– le membres calculés peuvent ˆetre utilisés dans la clause WHERE (c’est d’ailleurs la seule fa¸con d’effectuer
une tranche qui concerne plusieurs membres de base du cube).
Ordre de résolution
Il est parfois nécessaire de préciser dans quel ordre les membres calculés doivent ˆetre calculés. C’est
le cas notamment lorsque l’on combine pourcentage et différence.
Considérons l’exemple suivant :
1 WITH MEMBER temps.[de juillet 2001 a juillet 2002]
2 AS ’temps.[2002].juillet - temps.[2001].juillet’
3 MEMBER measures.[profit (en pourcentage)]
4 AS ’100 * (measures.montant - measures.cout) / measures.cout’
5 SELECT {measures.montant, measures.cout, measures[profit (\%)]} ON COLUMNS,
6 {temps.[2001].juillet, temps.[2002].juillet
7 temps.[de juillet 2001 a juillet 2002]} ON ROWS
8 FROM ventes
18 INTERROGER UN CUBE 93
Cette requˆete produit le résultat suivant : la dernière cellule ne contient pas forcément ce que l’on veut
montant cout profit (%)
juillet 2001 10186.12 8451.00 20
juillet 2002 9486.78 7569.50 25
de juillet 2001 a juillet 2002 -699.35 -881.5 -20
Pour obtenir la progression du profit en pourcentage il suffit de préciser que le membre calculé [de
juillet 2001 a juillet 2002] doit ˆetre calculé après le membre calculé [profit (%)] :
1 WITH MEMBER temps.[de juillet 2001 a juillet 2002]
2 AS ’temps.[2002].juillet - temps.[2001].juillet’,
3 SOLVE_ORDER = 2
4 MEMBER measures.[profit (en pourcentage)]
5 AS ’100 * (measures.montant - measures.cout) / measures.cout’,
6 SOLVE_ORDER = 1
7 SELECT {measures.montant, measures.cout, measures[profit (\%)]} ON COLUMNS,
8 {temps.[2001].juillet, temps.[2002].juillet
9 temps.[de juillet 2001 a juillet 2002]} ON ROWS
10 FROM ventes
Auquel cas nous obtenons bien le pourcentage recherché :
montant cout profit (%)
juillet 2001 10186.12 8451.00 20
juillet 2002 9486.78 7569.50 25
de juillet 2001 a juillet 2002 -699.35 -881.5 5
Mise en forme des membres calculés
D’autres options sont disponibles dans la clause MEMBER (cf. l’aide en ligne). Comme par exemple, une
description du format numérique `a employer :
1 WITH MEMBER measures.prix_unitaire
2 AS ’measures.montant / measures.quantite’,
3 FORMAT_STRING = ’#.## euros’
4 SELECT ...
18.4.2 Jeux nommés
Si un ensemble de membres est souvent utilisés dans des requˆetes MDX, il est intéressant de le définir
une bonne fois pour toutes et de lui donner un nom. C’est ce que l’on appelle un jeu (sous-entendu de
membres) nommé.
Si, par exemple, les 10 articles les plus vendus reviennent souvent alors on peut définir un jeu nommé
ainsi :
1 WITH SET MeilleursArticles -- le nom
2 AS ’TOPCOUNT(article.MEMBERS, 10, measures.quantite)’ -- l’expression
3 SELECT MeilleursArticles ON COLUMNS
4 FROM ventes
5 WHERE (measures.nb)
18 INTERROGER UN CUBE 94
Dans la définition d’un jeu nommé, on peut utiliser les fonctions ensemblistes UNION, EXCEPT et
INTERSECT. Exemple :
1 WITH SET MeilleursArticles
2 AS ’TOPCOUNT(article.MEMBERS, 10, (measures.quantite))’
3 SET ArticlesLesPlusCher
4 AS ’TOPCOUNT(article.MEMBERS, 10, (measures.prix_unitaire))’
5 SET MeilleursArticlesEtArticlesLesPlusCher
6 AS ’UNION(MeilleursArticles, ArticlesLesPlusCher)’
7 SET MeilleursArticlesSaufLesPlusCher
8 AS ’EXCEPT(MeilleursArticles, ArticlesLesPlusCher)’
9 SET MeilleursArticlesQuiSoientParmisLesPlusCher
10 AS ’INTERSECT(MeilleursArticles, ArticlesLesPlusCher)’
11 SELECT ...
18.4.3 Cellules calculées
Il existe un troisième objet que l’on peut définir dans la clause WITH, il s’agit des cellules calculées
(CELL CALCULATION). Mais cet objet est trop complexe pour entrer dans le cadre de ce document. Le
lecteur est donc dirigé vers l’aide en ligne et [12] pour découvrir cette notion.
18.4.4 Précisions
Si un intitulé comporte une quote ’, alors elle doit ˆetre doublée afin de ne par interférer avec la
délimitation de l’expression :
1 WITH MEMBER article.[Tous les albums de k’’s Choice]
2 AS ’SUM({[k’’s Choice - Cocoon Crash], [k’’s Choice - Paradise in me]})’
Si on désire introduire plusieurs notations dans la clause WITH, il suffit de les juxtaposer (les virgules
sont réservées aux propriétés des membres calculés) :
1 WITH MEMBER ... AS ’...’
2 MEMBER ... AS ’...’
3 SET ... AS ’...’
4 SELECT ...
18.5 Clause CELL PROPERTIES
Par ailleurs, on peut contrˆoler les propriétés de cellule que l’on veut afficher dans la fenˆetre contextuelle
(qui apparaˆit au clic droit sur une cellule) `a l’aide la dernière clause des requˆetes MDX. Par exemple,
pour n’afficher que l’ordinal et la valeur formattée :
1 SELECT ...
2 FROM ...
3 WHERE ...
4 CELL PROPERTIES CELL_ORDINAL, FORMATTED_VALUE
18 INTERROGER UN CUBE 95
18.6 Fonctions MDX
Dans ces requˆetes on peut `a tout moment utiliser une multitude d’autres fonctions offertes par MDX
(cf. l’aide en ligne et [12]). `A commencer par la fonction :
IIF(condition, si vrai, si faux )
Exemple : affichons oui ou non en deuxième colonne selon que les articles se sont vendus moins de
200 fois ou non :
1 WITH MEMBER measures.MauvaisArticle
2 AS ’IIF(measures.quantite < 200, "oui", "non")’
3 SELECT {measures.quantite, measures.MauvaisArticle} ON COLUMNS,
4 article.MEMBERS ON ROWS
5 FROM ventes
6 WHERE (temps.[2001])
MDX offre aussi la fonction ISEMPTY et qui permet de remplacer la valeur NULL par 0 (par exemple) :
1 WITH MEMBER measures.[quantite corrigee]
2 AS ’IIF(ISEMPTY(measures.quantite), 0, measures.quantite)
3 SELECT temps.[2003].CHILDREN ON COLUMNS, article.MEMBERS ON ROWS
4 FROM ventes
5 WHERE (measure.[quantite corrigee])
Remarque : dans la condition de la fonction IIF, on peut utiliser le mot-clé NOT.
Autre exemple, pour retrouver un ancˆetre : sélectionner la région dans laquelle se trouve la ville de Nice
1 SELECT {ANCESTOR(Nice,region)} ON COLUMNS
2 ...
Remarques :
– le premier argument doit ˆetre un membre unique ;
– le deuxième argument est soit le niveau auquel on monte, soit le nombre de niveaux `a monter.
Exemple pour retrouver les descendants : sélectionner les articles de la marque Channel
1 SELECT DESCENDANTS(Channel, article) ON COLUMNS
2 ...
Remarques :
– le premier argument doit ˆetre un membre unique ;
– le deuxième argument est soit le niveau auquel on descend, soit le nombre de niveaux `a descendre.
Dernier exemple : pour définir une colonne d’agrégat qui comprend la France et l’Italie par exemple
1 WITH MEMBER geographie.[France et Italie]
2 AS ’AGGREGATE({France, Italie})’
3 SELECT {France, Italie, [France et Italie]} ON COLUMNS,
4 Measures.MEMBERS ON ROWS
5 FROM ventes
La fonction AGGREGATE utilise alors la fonction d’agrégation appropriée `a chaque mesure.
18.7 Conclusion
On aboutit `a la stratégie suivante pour l’élaboration d’une requˆete MDX :
1. remplir la clause FROM avec le cube sur lequel on travaille ;
2. définir dans la clause WITH les membres calculés, les jeux nommés et les cellules calculées locaux ;
3. déterminer les tranches voulues pour remplir le tuple de la clause WHERE ;
4. pour chaque axe de la clause SELECT (et dans l’ordre) :
(a) déterminer les dimensions et les membres concernés ;
(b) filtrer éventuellement ces membres avec FILTER, NON EMPTY et/ou TOPCOUNT ;
(c) ordonner éventuellement les membres restants avec ORDER :
(d) lister après le mot-clé PROPERTIES les propriétés de membres (cf. §19.1 page 96) que l’on veut
ajouter aux propriétés de cellule.
5. lister dans la clause CELL PROPERTIES les propriétés de cellule (cf. §18.5 page 94) que l’on souhaite
avoir `a disposition.
Commentaires
Enregistrer un commentaire