Vous êtes sur la page 1sur 6

www.bewise.

fr
Accueil Articles Bewise TV KBs

Recherche
Blogs Projets Etudes de cas

10 requtes MDX utiles


Par Jean-Pierre Riehl, post le 28/01/2011 Profil : Dveloppeur | Niveau : Confirm (300) Tags : MDX, SQL Server, Analysis Services | Partager :

Introduction
Dans cet article, nous allons tudier quelques cas simples ncessitant d'avoir recours une requte MDX. Il est destin aux dveloppeurs dcisionnels qui pourront s'en aider pour crer des membres calculs ou concevoir des rapports plus complexes par exemple. Vous devez connatre le MDX pour cet article. Le langage MDX est le langage de requtage des bases de donnes multidimensionnelles (les cubes pour faire simple). Il est utilis par SQL Server Analysis Services (et dans sa forme standard par Hyperion). Le but de cet article n'est pas de vous apprendre le MDX. L'apprentissage de ce langage prend du temps car il est assez complexe (on doit penser en n-dimensions). J'irai donc l'essentiel en proposant des uses cases concrets et oprationnels.

Articles lis
- SQL Server 2000 Episode 1 : les fonctions - SQL Server 2000 - Episode II : XML - Crer ses attributs personnaliss pour accder aux donnes (1/3)

Quelques rappels MDX


Juste quelques rappels pour la bonne lecture de cet article :

A la base, un SELECT
La base d'une requte MDX est une instruction SELECT. Il est bien plus complexe qu'en SQL mais nous allons essayer de le formater toujours de cette faon :

SELECT { } on 0, * * on 1 FROM [Cube] WHERE { }

Set et tuple
Un Set pointe un ou plusieurs membres de dimension. Sa notation utilise les accolades {}. Ex :

{ [Date].&[1234] } ou { [Go].[Pays].[France] , [Go].[Pays].[Allemagne] ]


Un tuple est le croisement de dimensions et d'une mesure. On peut l'assimiler une cellule du cube. Sa notation utilise les parenthses (). Ex :

([Date].&[1234], [Measures].[Qt Vendue])

Membre calcul
Pour nos requtes nous aurons besoin de membres calculs. Evidemment, nous n'allons pas les crer dans le cube mais les injecter dans notre session. Pour cela, il faut utiliser la syntaxe suivante :

WITH MEMBER [xxx] AS statement> SELECT .

La base de donnes d'exemple


Je me base sur la base Adventure Works que vous pouvez trouver sur CodePlex. Il existe un DatawareHouse (AdventureWorks2008DW) et un projet Analysis Services qui vous permettra de dployer le cube. Ce projet est complet mais complexe car il fait intervenir toutes les notions et subtilit de SSAS. Sans rentrer dans le dtail, il vous permettra d'avoir un cube disposition sans avoir matriser toutes ces notions. Les tlchargements sont cette adresse : http://sqlserversamples.codeplex.com/#ssas

Les requtes
PROPERTIES()
Utilisation : Properties() est sans doute la fonction MDX que j'utilise le plus souvent avec CurrentMember ; principalement parce que l'un ne va pas sans l'autre. Properties permet de rcuprer une proprit sur un membre de dimension.

On distingue les proprits natives (dites intrinsques), inhrentes tout membre comme son nom unique, sa valeur, etc. mais aussi les proprits dfinies la construction du cube. On peut ainsi rcuprer un autre attribut ou une valeur lie au membre.

Exemple : Dans le premier exemple, on rcupre l'attribut Day Of Year pour lier le n du jour dans l'anne la date remonte sans faire de croisement de dimension.

WITH MEMBER JourDansAnnee AS [Date].[Calendar].CurrentMember.Properties("Day Of Year") SELECT {[JourDansAnnee], [Measures].[Internet Sales Amount]} ON 0, [Date].[Calendar].AllMembers ON 1 FROM [Adventure Works]
Dans le second exemple, on rcupre une proprit intrinsque qui est la valeur du membre, fortement type ; ici, on ramne la date.

WITH MEMBER [DateType] AS [Date].[Calendar].CurrentMember.Properties("Member_Value", TYPED) SELECT {[DateType], [Measures].[Internet Sales Amount]} ON 0, [Date].[Calendar].AllMembers ON 1 FROM [Adventure Works]
Evidemment pour ce second exemple, nous aurions pu crire :

[Date].[Calendar].CurrentMember.MEMBER_VALUE
L'usage le plus frquent que j'en fais est dans la construction d'un paramtre dans Report Builder. En effet, il faut non par rcuprer le label du membre mais son nom unique pour l'injecter dans la requte MDX. J'utilise donc la proprit MEMBER_UNIQUE_NAME de cette faon :

WITH MEMBER [ParameterCaption] AS [Date].[Calendar].CurrentMember.NAME MEMBER [ParameterUniqueName] AS [Date].[Calendar].CurrentMember.UNIQUENAME SELECT NON EMPTY {[ParameterCaption],[ParameterUniqueName]} ON 0, [Date].[Calendar].AllMembers ON 1 FROM [Adventure Works]
Note : On a toujours tendance naturellement tout dfinir comme attribut d'une dimension, pensez que si vous avez uniquement besoin d'une valeur pour de l'affichage, configurez l comme une proprit (cf. l'article suivant : http://blog.djeepy1.net/2010/05/21/tuning-des-attributs-de-dimension-dans-analysis-services/)

PARALLELPERIOD
Utilisation : La fonction ParallelPeriod permet de rcuprer un Set particulier dans une dimension temps. Plus prcisment, ParallelPeriod permet de rcuprer les membres quivalents un Set donn mais sur une priode antrieure ou future. Par exemple, si je suis sur janvier et fvrier 2008, je peux rcuprer janvier et fvrier sur une autre anne. Cette fonction est spcifique aux dimensions temporelles qu'Analysis Services traitent de faon spciale. Elle fonctionne sur les hirarchies dfinies par l'utilisateur. On lui passe les arguments suivants :

PARALLELPERIOD( Niveau, Nb de priode remonter, Set)


Le niveau dans la hirarchie, l'anne par exemple Le nombre de saut faire sur ce niveau (chiffre ngatif pour aller dans le futur) Les lments que l'on souhaite transposer Exemple : Dans cet exemple, on rcupre le mme jour mais sur le trimestre prcdent (1er avril 1er janvier) :

SELECT NON EMPTY {} ON 0, PARALLELPERIOD([Date].[Calendar].[Calendar Quarter], 1, [Date].[Calendar].[Date].&[20070401]) on 1 FROM [Adventure Works]


Dans cet autre exemple, on rcupre le tuple correspondant au mme jour l'anne prcdente :

WITH MEMBER [N-1] AS ( PARALLELPERIOD([Date].[Calendar].[Calendar Year], 1, [Date].[Calendar].CurrentMember), [Measures].[Sales Amount] ) SELECT {[Measures].[Sales Amount], [N-1]} ON 0, [Date].[Calendar].[Date].AllMembers ON 1 FROM [Adventure Works]
Cet exemple est le plus utilis pour faire des calculs de progression sur des priodes ou des KPI. Dans le mme genre : Quand on traite avec d'autres dimensions qui ne sont pas temporelles, on peut utiliser la fonction Cousin qui permet de naviguer de la mme faon dans une hirarchie.

YTD et PERIODSTODATE
Utilisation : YTD est l'acronyme de Year To Date. Encore une fois, cette fonction est spcifique aux dimensions de temps. Cette fonction a pour but de ramener un Set contenant l'ensemble des membres sur un niveau d'une hirarchie jusqu' un certain membre en commenant par le premier membre de l'anne. Par exemple, elle ramnera l'ensemble des dates entre le 1er janvier et une date donne. On utilise principalement cette fonction pour faire des cumuls ; et souvent en conjonction avec ParallelPeriod pour faire des comparaisons date date (comme un chiffre d'affaire date et son N-1). PeriodsToDate est la version gnrique de cette fonction qui permet de la gnraliser toute chelle de temps. Exemple : Dans cet exemple, on ramne l'ensemble des dates entre le 1er janvier et le 8 mai 2006

SELECT NON EMPTY {} ON 0, YTD([Date].[Calendar].[Date].&[20060508]) ON 1 FROM [Adventure Works]


Dans cet autre exemple, on calcule le cumul des ventes sur les semaines de la dimension :

WITH MEMBER [SalesYTD] AS AGGREGATE(YTD([Date].[Calendar Weeks].CurrentMember), [Measures].[Sales Amount]) SELECT {[Measures].[Sales Amount], [SalesYTD]} ON 0, [Date].[Calendar Weeks].[Calendar Week].AllMembers ON 1 FROM [Adventure Works]
Dans le mme genre : On trouve aussi les fonctions MTD et QTD respectivement pour Month To Date et Quarter To Date qui, vous l'aurez compris font la mme chose sur un mois ou un trimestre.

TAIL et HEAD
Utilisation : Ces fonctions permettent de rcuprer les n-premiers ou les n-derniers lments d'un Set. On peut l'utiliser pour rcuprer les 6 derniers mois par exemple. Exemple :

SELECT NON EMPTY {} ON 0, TAIL([Date].[Calendar].[Date].Members, 6) ON 1 FROM [Adventure Works]


Dans le mme genre : On trouve tout un wagon de fonctions permettant de manipuler les ensembles de membres. On peut citer Subset, Lag, PrevMember, ou Filter que nous verrons plus loin.

ORDER
Utilisation : Comme son nom l'indique, cette fonction permet d'ordonner un ensemble de membres. On peut ordonner par une des proprits de l'attribut comme sa valeur ou bien par des valeurs du cube. On utilise souvent cette fonction en combinaison avec Head ou Tail pour construire des Set dynamiques comme le Top 10 des clients. Attention quand on travaille avec des membres dans une hirarchie, l'ordre respectera le placement des membres dans celle-ci. Il faut prciser le paramtre BASC ou BDESC pour s'en affranchir. Exemple : Dans cet exemple, on renvoie les ventes par date dcroissante

SELECT {[Measures].[Internet Sales Amount]} on 0, ORDER([Date].[Calendar].AllMembers, [Date].[Calendar].CurrentMember.Value, BDESC) on 1 FROM [Adventure Works]
Dans cet autre exemple, on retourne la liste des promotions par chiffre d'affaires ralis en 2008.

SELECT {[Measures].[Sales Amount]} on 0, ORDER([Promotion].[Promotion].AllMembers, [Measures].[Sales Amount], DESC) on 1 FROM [Adventure Works] WHERE [Date].[Calendar].[Calendar Year].&[2008]
Dans le mme genre : On peut citer HIERARCHIZE qui permet d'ordonner des membres en respectant une hirarchie.

UNKNOWNMEMBER
Utilisation : L'UnkownMember, ou membre inconnu, est utilis pour grer les valeurs NULL du DatawareHouse (l'absence de valeur d'un point de vue mtier). Par exemple, si des lignes de vente n'ont pas de produit associ (ProductKey = NULL), elles seront relies aux Produits inconnus qui sera ce membre technique de la dimension produit.

Ce membre un peu particulier reste un membre part entire des dimensions qui remonte dans les requtes (et qui peut tre perturbant ou fausser des chiffres). Exemple : Dans cet exemple, on rcupre explicitement les ventes associes aucun produit

SELECT {[Measures].[Sales Amount]} ON 0, [Product].[Product].UNKNOWNMEMBER ON 1 FROM [Adventure Works]


Dans cet autre exemple, on souhaite exclure les ventes non affectes par exclusion de l'UnknownMember du Set sur l'axe 1.

SELECT {[Measures].[Sales Amount]} ON 0, {[Product].[Product].AllMembers - [Product].[Product].UNKNOWNMEMBER} ON 1 FROM [Adventure Works]


Dans le mme genre : Il n'existe pas de raccourci pour obtenir le membre racine (aussi appel All Member - ne pas confondre avec la fonction AllMembers). On utilisera une autre expression qui rcupre le premier lment de la dimension :

SELECT {[Measures].[Sales Amount]} ON 0, [Product].[Product].Members.Item(0) ON 1 FROM [Adventure Works]

STRTOSET
Utilisation : Cette fonction permet de convertir une chane de caractre en un Set utilisable dans une requte. On l'utilise notamment pour injecter des paramtres dans une requte. Attention ne pas abuser de cette fonction. Il m'est arriv de voir tout un jeu de membres calculs dans une solution bass sur des conversions de chanes, ce qui dgrade les performances. Exemple : Dans cet exemple, on injecte dynamiquement le n du mois dans la requte. La fonction STRTOSET transformera la chane de caractre au membre correspondant dans la dimension date.

SELECT {[Measures].[Sales Amount]} ON 0, [Sales Territory].[Sales Territory Country].Members ON 1 FROM [Adventure Works] WHERE STRTOSET("[Date].[Calendar].[Month].&[2008]&[" + @NumMois + "]")
Dans le mme genre : Il existe le parfait inverse STRTOSET qui transforme un ensemble de membre en chane de caractres : c'est SETTOSTR. Dans le mme style on citera SETTOARRAY, STRTOMEMBER, TUPLETOSTR, etc.

FILTER
Utilisation : Filter permet, comme son nom l'indique, de filtrer un ensemble de membre en fonction d'une expression. Contrairement ce que l'on peut imaginer, la clause WHERE en MDX permet de pointer un sous-cube ou un slice dans le cube, c'est pourquoi elle n'est pas de la forme Dimension = Valeur mais attend un Set. En revanche, la fonction FILTER fonctionne quasiment comme la clause WHERE en SQL. On lui passe les arguments suivants :

FILTER( Set de base, Condition)


Le Set de base est l'ensemble de membres sur lequel s'effectue la recherche ; on prend souvent AllMembers. La condition, une expression qui doit renvoyer vrai ou faux. La condition peut porter sur une mesure du cube ou bien sur une proprit de dimension Exemple : Dans ce premier exemple, on rcupre les ventes pour un produit donn. On utilise souvent ce type de requte de faon paramtre avec des dimensions forte cardinalit (une rfrence par exemple) :

SELECT {[Measures].[Sales Amount]} ON 0, FILTER([Product].[Product].Members, [Product].[Product].CurrentMember.Name = "Casque" ) ON 1 FROM [Adventure Works]


Dans cet autre exemple, on filtre sur la valeur d'une mesure, ici les revendeurs avec un CA de plus de 100 000$ :

SELECT {[Measures].[Reseller Sales Amount]} ON 0, FILTER([Reseller].[Reseller].Members, [Measures].[Reseller Sales Amount] > 100000) ON 1 FROM [Adventure Works]
Dans le mme genre : Dans le cas o l'on filtre sur une mesure, on peut privilgier l'utilisation de fonctions comme TOPCOUNT, TOPSUM ou TOPPERCENT pour ramener la fourchette haute d'un Set (cf. aussi les fonctions TAIL/HEAD prsentes ci-dessus).

AGGREGATE
Vous utilisez implicitement la fonction AGGREGATE en permanence sans le savoir. Le simple fait de requter un tuple appelle la fonction d'agrgation. Ecrire cette requte.

SELECT ([Measures].[Sales Amount]) ON 0 FROM [Adventure Works]


.implique qu'on agrge les ventes sur toutes les dimensions. On peut la traduire par le tuple suivant :

SELECT ( [Measures].[Sales Amount], [Date].[Calendar].[All Periods], [Product].[Product Categories].[All Products], ... ) ON 0 FROM [Adventure Works]
On peut remplacer un membre par un Set mais tout change quand on passe le tuple form en tant que membre calcul. On obtient l'erreur suivante : la fonction attend une expression de chane ou numrique pour l'argument. Une expression d'ensemble de tuples a t utilise.

WITH MEMBER [Ventes] AS ( {[Date].[Calendar].[Calendar Year].&[2005],[Date].[Calendar].[Calendar Year].&[2006]}, [Measures].[Sales Amount] ) SELECT {[Ventes]} ON 0 FROM [Adventure Works]

Dans un membre calcul, il faut prciser explicitement l'agrgation via la fonction AGGREGATE qui utilisera la fonction d'agrgation dfinie pour la mesure dans le cube.

WITH MEMBER [Ventes] AS AGGREGATE( {[Date].[Calendar].[Calendar Year].&[2005],[Date].[Calendar].[Calendar Year].&[2006]}, [Measures].[Sales Amount] ) SELECT {[Ventes]} ON 0 FROM [Adventure Works]
Dans le mme genre : AGGREGATE s'appuie sur ce qui est dfini comme fonction d'agrgation dans le cube. Mais on peut vouloir forcer une somme avec SUM, une moyenne avec AVG (c'est d'ailleurs le seul moyen de faire une moyenne, via un membre calcul) ou un comptage avec COUNT. Evidemment, il en existe bien d'autres.

EXISTS et NONEMPTY
Utilisation : Un besoin frquent est de rcuprer les membres d'une dimension pour lesquels il existe des valeurs. C'est souvent le cas quand on veut remplir un paramtre (dans Report Builder par exemple) en limitant les valeurs un certain contexte. Il y a de nombreuses faons de le faire dont certaines ont t voques ici mais les fonctions EXISTS et NONEMPTY remplissent aussi ce rle et surtout seront utilisables dans un membre calcul. Exemple : Dans cet exemple, on rcupre la liste des dates pour lesquelles une vente particulire existe (ici un produit en particulier).

SELECT {} ON 0, EXISTS( [Date].[Date].Members,[Product].[Product Categories].[Product].&[348], "Internet Sales" ) ON 1 FROM [Adventure Works]


On retrouve le mme rsultat avec NONEMPTY.

SELECT NONEMPTY( [Date].[Date].Members, ([Measures].[Sales Amount],[Product].[Product Categories].[Product].&[348]) ) ON 0 FROM [Adventure Works]


Enfin, on peut aussi slicer le cube avec une clause WHERE mais l on exclut la possibilit de crer un membre calcul directement dans le cube.

SELECT {} ON 0, {[Date].[Date].Members} ON 1 FROM [Adventure Works] WHERE {[Product].[Product Categories].[Product].&[348]}

Conclusion
En passant en revue des fonctions MDX, nous avons pu voir de nombreuses requtes utiles pour explorer un cube ou crer des membres calculs. Evidemment, la spcificit des mtiers analyser fait qu'il est difficile d'avoir un jeu prcis de requtes. Nanmoins, une bonne connaissance du catalogue de fonctions MDX permet de maitriser la navigation dans les dimensions et les mesures. Dans la ralit, on s'appuie bien videmment en premier lieu sur les designers de requte comme celui de Report Builder qui inclut la gestion des paramtres. Mais il est de temps en temps ncessaire de rentrer dans le code MDX gnr pour l'optimiser, l'arranger ou le simplifier. La notion de performance n'a pas t aborde dans cet article. En effet, il y a souvent de nombreuses faons d'crire les requtes MDX et une des consquences peut tre les performances meilleures ou moins bonnes avec l'une ou l'autre criture. Mais notez bien que, comme pour le moteur SQL, il y a une phase de parsing et d'optimisation qui conduisent souvent une criture commune et optimise par le moteur OLAP lui-mme. C'est pourquoi il faut toujours prendre en compte l'aspect lisibilit et maintenabilit d'une requte ; dj que ce langage est complexe.

Je suis MVP SQL Server, consultant, manager, quelquefois architecte mais principalement geek. Tomb petit dans le code, jai pass les tapes classiques de linformaticien. BASIC, Pascal, VB6, ASP 3.0, .NET 1.0 beta 1, SQL Server 2008 R2. De la maison lEPITA, de Paris Toulouse, du lecteur de cassette au SAN. Je suis maintenant ultra spcialis Voir les autres publications de l'auteur

Commentaires
J'aime

Ajouter un nouveau commentaire

S'identifier

Afficher 0 commentaires
' S'abonner par courrier lectronique + RSS

Tri: les plus populaires