• Il Linguaggio MDX – MultiDimensional eXpressions

Transcript

• Il Linguaggio MDX – MultiDimensional eXpressions
Lezione 12 - C
•
Il Linguaggio MDX –
MultiDimensional eXpressions
08/03/2010
1
Il Linguaggio MDX
Il linguaggio MDX (MultiDimensional eXpression) è usato per
recuperare e manipolare dati multidimensionali in SQL Server
Analysis Services, quali i dati archiviati in cubi
Come una query SQL, ogni query MDX comporta una richiesta di
dati (la clausola SELECT), un'origine (la clausola FROM) e un filtro
(la clausola WHERE): estrazione di parti specifiche di dati da un
cubo per l'analisi.
MDX ha una sintassi simile a SQL ma la semantica è diversa
In alcuni aspetti è molto verboso e ridondante tuttavia, è possibile
omettere nelle espressioni alcune parti significative, la cui
interpretazione è basata su regole di default
MDX non è un linguaggio di interrogazione in senso stretto :
permette di calcolare, a partire da un cubo, un dataset che ha una
struttura simile a un cubo
Tuttavia, il risultato di una interrogazione MDX non è, propriamente,
un cubo
– MDX non è un linguaggio chiuso
– MDX non può essere usato per la definizione di viste
2
Schemi Multi-Dimensionali in Analysis
Services
Dimensioni e attributi dimensionali si chiamano livelli
I valori delle dimensioni e degli attributi dimensionali si dicono membri
livelli
dimensione STORE
(ALL)
membri
STORE
CITY
STATE
COUNTRY
(ALL)
Ditutto
RE
EmiliaR
Italia
ALL
NonSoloX
RE
EmiliaR
Italia
ALL
NonSoloY
MO
EmiliaR
Italia
ALL
NonSoloZ
RM
Lazio
Italia
ALL
...
...
...
...
ALL
Per denotare un membro (le [ ] sono facoltative) :
– [STORE].[ALL].[Italia].[EmiliaR].[RE] : percorso completo
– [STORE].[RE] : se il membro “RE” è univoco nella dimensione STORE
– [CITY].[RE] : se il livello CITY è univoco in tutte le dimensioni del cubo
3
Eventi e Aggregazione: Tuple
Una tupla è una ennupla di membri denotati tra parentesi ()
Una tupla costituita da un membro per ciascuna dimensione individua un
evento primario:
([data].[15/5/2004],[prodotto].[brillo], [store].[DiTutto])
In altri termini è una tupla corrispondente al pattern primario.
Un evento secondario è individuato da una tupla corrispondente ad un
pattern secondario
–
([data].[15/5/2004],[prodotto].[brillo]) corrisponde al Pattern {Data,Prodotto}
–
([mese].[5/2004],[prodotto].[brillo], [store].[DiTutto])
corrisponde al Pattern {Mese,Prodotto,Store}
–
([mese].[5/2004],[prodotto].[brillo],[City].[RE])
corrisponde al Pattern {Mese,Prodotto,City}
MDX usa il concetto di tupla anche per estrarne i valori delle misure.
–
([data].[15/5/2004],[prodotto].[brillo],
[store].[DiTutto],
Measures.[incasso])
il valore della misura Incasso è riferito all’evento primario
–
([mese].[5/2004],[prodotto].[brillo],
[store].[DiTutto],
Measures.[incasso])
il valore della misura Incasso è riferito all’evento secondario,
4
ovvero è calcolato dopo aver aggregato su mese
Il Cubo delle Vendite
negozio
10
BigWare
parte
vite
data
10-10-2001
Tupla MDX per identificare l’evento primario:
(data.[10-10-2001], parte.[vite], negozio.[BigWare])
Tupla MDX per identificare l’evento primario e estrarre Incasso:
(data.[10-10-2001], parte.[vite], negozio.[BigWare],Measures.[Incasso])
5
MDX: Istruzione SELECT
L’istruzione SELECT di MDX consente di selezionare i dati da un cubo
negozio
Una prima possibilità
per selezionare la cella
in figura ed elencarne la
misura Incasso è
tramite
la seguente
query MDX:
10
BigWare
parte
data
vite
10-10-2001
SELECT
Measures.[Incasso]
FROM CuboVendite
WHERE (data.[10-10-2001], parte.[vite], negozio.[BigWare])
In effetti Measures.[Incasso] deve essere Measures.[Incasso] ON
AXIS(0)
6
Struttura delle Interrogazioni MDX
Nella versione più semplice, la struttura delle interrogazioni MDX è:
SELECT specifica_asse {, specifica_asse}
FROM nome_cubo
WHERE specifica_slicer
Gli assi sono le “dimensioni” del risultato ovvero, gli elementi che
devono comporre l’intestazione del risultato
- Ogni asse specifica un insieme di tuple
Lo slicer contiene le condizioni di selezione
Il risultato di una interrogazione è una struttura multidimensionale, chiamata
dataset, è organizzata mediante uno o più assi, detti, in ordine,
COLUMNS, ROWS, PAGES, SECTIONS e CHAPTERS oppure AXIS(0), AXIS(1), AXIS(2), ...
7
Cubi in MDX : Dataset
Così come l’istruzione SELECT in SQL restituisce una tabella,
l’istruzione SELECT in MDX restituisce un cubo (dataset)
Un’altra possibilità per selezionare la cella in figura è quella di
costruire un nuovo dataset costituito dalla sola cella
negozio
Il nuovo dataset ha tre dimensioni :
AXIS(0), AXIS(1) e AXIS(2)
Non avendo posto nessuna
condizione sulle Measures in tale
dataset ci saranno tutte le misure
10
BigWare
parte
data
10-10-2001
{ (data.[10-10-2001]) } ON AXIS(0),
{ (parte.[vite]) } ON AXIS(1),
{(negozio.[BigWare]) } ON AXIS(2)
FROM CuboVendite
vite
SELECT
8
Per Selezionare più Celle
negozio
10 30
BigWare
’15/4/2001'
data
'5/4/2001'
parte
vite
Si può costruire il dataset formato dalle due celle tramite la query:
SELECT
{ ([data].[5/4/2001]), ([data].[15/4/2001]) } ON AXIS(0),
{ ([parte].[vite]) } ON AXIS(1),
{ ([negozio].[BigWare]) } ON AXIS(2)
FROM CuboVendite
Non si può ottenere l’incasso complessivo nelle due date di Vite in BigWare:
Servirebbe una condizione WHERE con OR:
([data].[5/4/2001]) OR ([data].[15/4/2001])
ma questo non è consentito in MDX!
Per ottenere l’incasso complessivo occorrerà usare un membro calcolato.
9
MDX: Slicing
negozio
Fissando il valore per una dimensione (ad esempio, per Negozio) si
ottiene un dataset bidimensionale
Sulle altre dimensioni (esempio Data) si devono riportare tutti i valori
assunti da tale dimensione, ovvero tutti i membri della dimensione:
[data].MEMBERS
'DiTutto'
SELECT
data.MEMBERS ON AXIS(0),
prodotto.MEMBERS ON AXIS(1)
FROM CuboVendite
WHERE (negozio.[DiTutto])
data
Il precedente dataset si può
ancora considerare come
tridimensionale, ma con una
dimensione che assume un
unico valore:
SELECT
data.MEMBERS ON AXIS(0),
prodotto.MEMBERS ON AXIS(1),
{(negozio.[DiTutto]) } ON AXIS(2)
FROM CuboVendite
10
MDX: Slicing
negozio
Fissando il valore per due dimensioni si ha un dataset unidimensionale
'DiTutto'
SELECT
prodotto.MEMBERS ON AXIS(1)
FROM CuboVendite
WHERE (negozio.[DiTutto], data.[5/4/2001] )
'5/4/2001'
data
Il precedente dataset si può
ancora considerare come
tridimensionale, ma con due
dimensioni che assumono
un unico valore:
SELECT
{(data.[5/4/2001])} ON AXIS(0),
prodotto.MEMBERS ON AXIS(1),
{(negozio.[DiTutto]) } ON AXIS(2)
FROM CuboVendite
11
Aggregazione
tipo
città
mese
tipo
Σ
negozio
mese
Σ
parte
data
12
MDX: Aggregazione
città
Tupla MDX per identificare
l’evento secondario
42
RE
Frutta
mese
tipo
([data].[mese].[Marzo],
[parte].[tipo].[Frutta],
[negozio].[citta].[RE])
Marzo
Query MDX per selezionare la misura Incasso:
SELECT
Measures.[Incasso]
FROM CuboVendite
WHERE ([data].[mese].[Marzo], [parte].[tipo].[Frutta], negozio.[citta].[RE])
Il valore restituito è calcolato sulla base degli operatori di
aggregazione
13
MDX: Aggregazione
città
42
RE
tipo
Frutta
mese
Marzo
Anche nel caso dell’aggregazione, è possibile selezionare la macrocella costruendo un nuovo dataset costituito dalla sola cella :
SELECT
{ ([data].[mese].[Marzo])} ON AXIS(0),
{ ([parte].[tipo].[Frutta]) } ON AXIS(1),
{ ([negozio].[citta].[RE]) } ON AXIS(2)
FROM CuboVendite
Il valore associato alla macro-cella è calcolato sulla base degli
operatori di aggregazione
14
MDX: Aggregazione
città
42 58
RE
tipo
Frutta
mese
Marzo Aprile
Si può costruire il dataset formato dalle due macro-celle tramite la query:
SELECT
{ ([data].[mese].[Marzo]), [data].[mese].[Aprile]} ON AXIS(0),
{ ([parte].[tipo].[Frutta]) } ON AXIS(1),
{ ([negozio].[citta].[RE]) } ON AXIS(2)
FROM CuboVendite
Come nel caso di singole celle, non è possibile ottenere l’incasso complessivo
dei due mesi: occorrerà anche in questo caso definire (nella query MDX)
un membro calcolato.
15
MDX: Aggregazione
Come ottenere tutte le macro-celle dell’aggregazione ?
città
tipo
Sul secondo asse devo riportare
tutti i valori assunti da tipo,
ovvero tutti i membri del livello
tipo:
[parte].[tipo].MEMBERS
mese
SELECT
[data].[mese].MEMBERS ON AXIS(0),
[parte].[tipo].MEMBERS ON AXIS(1),
[negozio].[citta].MEMBERS ON AXIS(2)
FROM CuboVendite
Si noti che la funzione MEMBERS costruisce un insieme quindi è inutile usare
le { … } nella costruzione degli assi
16
MDX: Aggregazione e Slicing
Dataset bidimensionale, ottenuto fissando il valore ad una dimensione:
città
mese
SELECT
[data].[mese].MEMBERS ON AXIS(0),
[negozio].[citta].MEMBERS ON AXIS(1)
FROM CuboVendite
WHERE ([parte].[tipo].[Bevanda])
Dataset tridimensionale, in cui una dimensione assume un solo valore:
città
tipo
mese
Bevanda
SELECT
[data].[mese].MEMBERS ON AXIS(0),
{ ([parte].[tipo].[Bevanda]) } ON AXIS(1),
[negozio].[citta].MEMBERS ON AXIS(2)
FROM CuboVendite
17
MDX non è un Linguaggio Chiuso
Non si può creare una vista ed interrogarla!
città
città
tipo
mese
CREATE VIEW
PROVA(mese,tipoparte,cittaneg)
AS SELECT
data.[mese].MEMBERS ON AXIS(0),
parte.[tipo].MEMBERS ON AXIS(1),
negozio.[citta].MEMBERS ON AXIS(2)
FROM CuboVendite
mese
SELECT
mese.MEMBERS ON AXIS(0),
cittaneg.MEMBERS ON AXIS(1)
FROM PROVA
WHERE (tipoparte.[Bevanda])
18
Dove e Come utilizzare MDX?
Dove e come utilizziamo SQL?
– Esecuzione interattiva di interrogazioni (es SQL Query Analyzer)
– Interrogazioni incorporate in un’applicazione client:
Import/export dati in DTS
applicazioni che accedono tramite ODBC
– embedded SQL
Il linguaggio MDX è usato (ad oggi) solo in contesti specifici
– MDX Sample Application: applicazione per l’esecuzione interattiva di
interrogazioni MDX con risultati bidimensionali
– Interrogazioni MDX incorporate in un’applicazione client:
“Office OLAP Components”, quali
“Pivot Table Service”
“Excel Pivot Table”
19
MDX Sample Application - MDX SA
Si consideri il seguente cubo e la seguete query MDX:
negozio
1030
BigWare
’15/4/2001'
data
'5/4/2001'
par
te
vite
SELECT
{ (data.[5/4/2001]), (data.[15/4/2001]) } ON AXIS(0),
{ (parte.[vite]) } ON AXIS(1),
{(negozio.[BigWare]) } ON AXIS(2)
FROM CuboVendite
Come visualizzarlo in modo bidimensionale con MDX SA?
SELECT
{(negozio.[BigWare]) } ON COLUMNS,
{ (parte.[vite],data.[5/4/2001]), (parte.[vite],data.[15/4/2001]) } ON ROWS
FROM CuboVendite
VITE
5/4/2001
15/4/2001
BIGWARE
10
30
20
Cubo Sales (database FoodMart)
dimensione Time; livelli Year, Quarter, Month
dimensione Product; livelli (All), Product Family, Product Department,
Product Category, Product Subcategory, Brand Name, Product Name
dimensione Store; livelli (All), Store Country, Store State, Store City, Store
Name
dimensione Customers; livelli (All), Country, State Province, City, Name
dimensione Education Level; livelli (All), Education Level
dimensione Gender; livelli (All), Gender
dimensione Marital Status; livelli (All), Marital Status
dimensione Yearly Income; livelli (All), Yearly Income
dimensione Promotion Media; livelli (All), Media Type
dimensione Promotions; livelli (All), Promotion Name
misure (Measures); membri Unit Sales, Store Cost, Store Sales, Sales
Count, Store Sales Net
21
Esempio di interrogazione MDX
Totale delle unità di vendita vendute raggruppate per anno
SELECT
{([Measures].[Unit Sales])} ON COLUMNS,
{([Time].[Year].MEMBERS)} ON ROWS
FROM [Sales]
Esecuzione dell’interrogazione in MDX SA
22
Operatore punto
L’operatore punto . è usato
per accedere a un livello di una dimensione : [Time].[Year]
per accedere a un membro di una dimensione : [Time].[1997]
per eseguire una operazione:
[Time].[Year].MEMBERS è una espressione che restituisce l’insieme
dei membri del livello [Time].[Year]
Esempio : calcolare il totale di ogni misura raggruppato per anno
SELECT
{([Measures].MEMBERS)} ON COLUMNS,
{([Time].[Year].MEMBERS)} ON ROWS
FROM [Sales]
23
Tuple e dimensionalità
Una tupla può includere sia membri di più dimensioni
([Time].[1997],[Store].[Canada])
sia più membri di una stessa dimensione.
([Time].[1997], [Time].[1997].[Q1])
Il termine dimensionalità viene utilizzato per indicare le dimensioni
descritte dai membri di una tupla.
–
Le seguenti due tuple hanno la stessa dimensionalità
1. ([Time].[1997],[Store].[Canada])
2. ([Time].[1997],[Store].[USA])
–
Le seguenti due tuple non hanno la stessa dimensionalità
1. ([Time].[1997],[Store].[Canada])
2. ([Store].[USA],[Time].[1997])
24
Set di tuple
Un set è un insieme ordinato di zero, una o più tuple.
I set si denotano tramite parentesi graffe { … } :
{([Time].[1997],[Store].[Canada]),([Time].[1997], [Store].[USA])}
Il set può essere calcolato:
{([Time].[Year].MEMBERS)}
In tal caso non è necessario introdurre le { … }
Set e dimensionalità
Le tuple all'interno di un set devono avere la stessa dimensionalità:
{([Time].[1997]),([Time].[1997].[Q1])}
{([Time].[1997],[Store].[Canada])([Time].[1997],[Store].[USA])}
Le seguenti espressioni non sono corrette:
{([Time].[1997]), [Store].[Canada])}
{([Time].[1997],[Store].[Canada])([Store].[USA],[Time].[1997])}
25
Specifica degli assi
La specifica di un asse è una espressione che descrive un set di tuple
Esempio: Calcolare i totali delle vendite (di ogni misura) nel 1997
SELECT
{([Measures].MEMBERS)} ON COLUMNS,
{([Time].[1997])} ON ROWS
FROM [Sales]
Esempio: Calcolare i totali delle vendite (di ogni misura) nel 1997 e
nel primo trimestre 1997
SELECT
{([Measures].MEMBERS)} ON COLUMNS,
{([Time].[1997]), ([Time].[1997].[Q1])} ON ROWS
FROM [Sales]
26
Specifica degli assi
L'ordine delle tuple in un set ha effetto sull'ordine di nidificazione in
una dimensione dell'asse.
Esempio: Calcolare i totali delle vendite (di ogni misura) nel 1997 e
nel 1998 per il Canada e gli Stati Uniti:
SELECT
{([Measures].MEMBERS)} ON COLUMNS,
{([Time].[1997], [Store].[Canada]),
([Time].[1997], [Store].[USA]),
([Time].[1998], [Store].[Canada]),
([Time].[1998], [Store].[USA])} ON ROWS
FROM [Sales]
Scambiando l’ordine si ottiene
27
CROSSJOIN
L’operatore di CROSSJOIN consente la specifica di un asse come
prodotto cartesiano di due (o più ... ) insiemi
Esempio, se si vogliono raggruppare dei dati su un asse per anno e
nazione, per tutti gli anni e per il Canada e gli USA
SELECT
{([Measures].MEMBERS)} ON COLUMNS,
CROSSJOIN({[Time].[Year].MEMBERS},
{[Store].[Canada], [Store].[USA]})ON ROWS
FROM [Sales]
28
NONEMPTYCROSSJOIN
L’operatore di NONEMPTYCROSSJOIN equivale al CROSSJOIN
ma visualizza soltanto le righe contenenti celle non vuote
Il CROSSJOIN con più di due insiemi non può essere eseguito in
MDX Sample Application (la loro visualizzazione risulterebbe
problematica ...): si deve usare NONEMPTYCROSSJOIN
Ad esempio, se si vogliono raggruppare dei dati su un asse per
anno, nazione e sesso, per tutti gli anni e per il Canada e gli USA
SELECT {([Measures].MEMBERS)} ON COLUMNS,
NONEMPTYCROSSJOIN({[Time].[Year].MEMBERS},
{[Store].[Canada],[Store].[USA]},
[Gender].Members)ON ROWS FROM [Sales]
29
MDX: PRINCIPALI OPERATORI
x.MEMBERS : insieme dei membri della dimensione o livello x
m.CHILDREN : insieme dei figli del membro m
– Esempio: Calcolare i totali di ogni misura per ogni stato degli USA
SELECT
{([Measures].MEMBERS)} ON COLUMNS,
{([Store].[USA].CHILDREN)} ON ROWS
FROM [Sales]
DESCENDANTS(m,l) :
insieme dei discendenti del membro m al livello l
– Esempio: Calcolare i totali di ogni misura per ogni città degli USA
SELECT
{([Measures].MEMBERS)} ON COLUMNS,
DESCENDANTS([Store].[USA], [Store City]) ON ROWS
FROM [Sales]
30
MDX: la clausola di selezione WHERE
La clausola WHERE specifica condizioni di selezione dell’interrogazione
la condizione di selezione assume solitamente la forma di una congiunzione di
uguaglianze, espresse tramite una tupla
Esempio: calcolare il totale delle unità vendute per anno, limitatamente alle
vendite negli USA
SELECT
{([Measures].[Unit Sales])} ON COLUMNS,
[Time].[Year].MEMBERS ON ROWS
FROM [Sales]
WHERE ([Store].[Store Country].[USA])
Esempio: calcolare il totale delle unità vendute per anno, limitatamente alle
vendite effettuate negli USA dagli uomini
SELECT
{([Measures].[Unit Sales])} ON COLUMNS,
[Time].[Year].MEMBERS ON ROWS
FROM [Sales]
WHERE ([Store].[Store Country].[USA], [Gender].[M])
31
MDX: la clausola di selezione WHERE
Una condizione di selezione nel WHERE non può essere relativa a una
dimensione usata nella specifica di un asse
Esempio: calcolo unità vendute per trimestre, limitatamente al 1997
– la seguente interrogazione non è corretta
SELECT
{([Measures].[Unit Sales])} ON COLUMNS,
{([Time].[Quarter].MEMBERS)} ON ROWS
FROM [Sales]
WHERE ( [Time].[Year].[1997])
– per esprimere i trimestri del 1997 occorre usare DESCENDANT
SELECT
{([Measures].[Unit Sales])} ON COLUMNS,
DESCENDANTS ([Time].[1997], [Quarter]) ON ROWS
FROM [Sales]
32
MDX: la clausola di selezione WHERE
Una condizione di selezione non può vincolare una stessa
dimensione a più membri
Ad esempio, la seguente interrogazione non è corretta
SELECT
{([Measures].[Unit Sales])} ON COLUMNS,
{([Time].[Year].MEMBERS)} ON ROWS
FROM [Sales]
WHERE ([Store].[Store Country].[USA],
[Store].[Store Country].[Canada])
per considerare le vendite complessive degli USA e del Canada
bisogna usare i membri calcolati (vedi più avanti)
33
INTERPRETAZIONI DI DEFAULT: misure
le misure sono membri di Measures: la prima è [Unit Sales]
SELECT
{([Store].[USA].CHILDREN)} ON COLUMNS,
{([Time].[Year].MEMBERS)} ON ROWS
FROM [Sales]
questa interrogazione è equivalente alla seguente
SELECT
{([Store].[USA].CHILDREN)} ON COLUMNS,
{([Time].[Year].MEMBERS)} ON ROWS
FROM [Sales]
WHERE ([Measures].[Unit Sales])
In questa interrogazione l’aggregazione viene calcolata
– rispetto alla misura specificata nella condizione di selezione
– usando la funzione di aggregazione associata per default (nella definizione
del cubo) alla misura selezionata
34
Membri calcolati
In una interrogazione MDX si possono definire nuovi membri calcolati con lo stesso
significato e semantica dei membri calcolati in Analysis Services
– essi sono utili per definire nuove misure che servono solo all’interno della
specifica interrogazione
sintassi delle interrogazioni con la definizione di membri calcolati
WITH MEMBER specifica_membro
{MEMBER specifica_membro}
SELECT ....
Esempio calcolare il profitto per anno per categoria di prodotto
WITH MEMBER [Measures].[Store Profit] AS
'[Measures].[Store Sales] [Measures].[Store Cost]'
SELECT
{([Time].[Year].MEMBERS)} ON COLUMNS,
{([Product].[Product Category].MEMBERS)} ON ROWS
FROM [Sales]
WHERE ([Measures].[Store Profit])
35
Membri calcolati :esempi
Calcolare il profitto per categoria di prodotto, per l’anno 1997
WITH MEMBER [Measures].[Store Profit] AS
'[Measures].[Store Sales] [Measures].[Store Cost]'
SELECT
{([Measures].[Store Profit])} ON COLUMNS,
{([Product].[Product Category].MEMBERS)} ON ROWS
FROM [Sales]
WHERE ([Time].[Year].[1997])
WITH MEMBER [Measures].[Store Profit] AS
'([Time].[Year].[1997], [Measures].[Store Sales]) ([Time].[Year].[1997], [Measures].[Store Cost])'
SELECT
{([Measures].[Store Profit])} ON COLUMNS,
{([Product].[Product Category].MEMBERS)} ON ROWS
FROM [Sales]
36
Membri calcolati : esempi
I membri calcolati possono essere usati come i membri “ordinari”
WITH MEMBER [Measures].[Store Profit] AS
'[Measures].[Store Sales] - [Measures].[Store Cost]'
MEMBER [Measures].[Store Percent Profit] AS
'[Measures].[Store Profit] / [Measures].[Store Cost]'
SELECT
{([Measures].[Store Profit]),
([Measures].[Store Percent Profit])} ON COLUMNS,
{([Product].[Product Category].MEMBERS)} ON ROWS
FROM [Sales]
WHERE ([Time].[Year].[1997])
37
Membri calcolati sulle dimensioni
In Analysis Service è possibile definire un membro calcolato sulla base dei
valori delle misure in corrispondenza di due o più membri delle dimensioni
Inoltre si può scegliere a quale dimensione appartiene il nuovo membro
calcolato, cioè non deve essere necessariamente un membro di Measures
– Esempio: differenza dei valori assunti dalle misure in corrispondenza dei
membri [Time].[1998] e [Time].[1997] : si definisce il membro calcolato
[Time].[1998] - [Time].[1997]
come appartenente alla dimensione
[Time]
38
Membri calcolati sulle dimensioni in MDX
Si può definire un membro calcolato sulle dimensioni anche in una query MDX
– Ad esempio, si può definire in MDX lo stesso membro calcolato precedente
come membro nella dimensione Time per indicare “la differenza tra il 1998
e il 1997”
– WITH MEMBER [Time].[1998 - 1997] AS
'[Time].[1998] - [Time].[1997]'
SELECT
{([Time].[1997]), ([Time].[1998]),
([Time].[1998 - 1997])} ON COLUMNS,
{([Product].[Product Family].MEMBERS)} ON ROWS
FROM [Sales]
WHERE ([Measures].[Unit Sales])
39
Membri calcolati : un esempio più complesso
WITH
MEMBER [Measures].[Store Profit] AS
'[Measures].[Store Sales] - [Measures].[Store Cost]'
MEMBER [Time].[1998 - 1997] AS '[Time].[1998] - [Time].[1997]'
SELECT
{([Measures].[Store Sales]), ([Measures].[Store Cost]),
([Measures].[Store Profit])} ON COLUMNS,
{([Time].[1997]), ([Time].[1998]), ([Time].[1998 - 1997])} ON
ROWS
FROM [Sales]
40
Ordine di valutazione
In presenza di più membri calcolati occorre considerare l’ordine di valutazione
Esempio: Rapporto del profitto tra i primi due trimestri del 1997
– calcolare prima i profitti dei due trimestri e poi il loro rapporto
WITH
MEMBER [Measures].[Store Profit] AS
'[Measures].[Store Sales] - [Measures].[Store Cost]'
MEMBER [Time].[1997].[Q1 / Q2] AS '[Time].[1997].Q1 / [Time].[1997].Q2'
SELECT
{([Measures].[Store Sales]), ([Measures].[Store Cost]),
([Measures].[Store Profit])} ON COLUMNS,
{([Time].[1997].Q1), ([Time].[1997].Q2), ([Time].[1997].[Q1 / Q2])} ON ROWS
FROM [Sales]
Questa interrogazione non è corretta in quanto restituisce:
Nota :
le cifre decimali sono indicate in alcuni casi con la ‘,’ in altri con il ‘.’
Dipende dal sistema installato
41
Ordine di valutazione: SOLVE_ORDER
Per calcolare prima i profitti dei due trimestri e poi il loro rapporto occorre stabilire
esplicitamente l’ordine di valutazione tramite la clausola SOLVE_ORDER:
il membro con SOLVE_ORDER più basso verrà calcolato per prima
WITH
MEMBER [Measures].[Store Profit] AS
'[Measures].[Store Sales] - [Measures].[Store Cost]',
SOLVE_ORDER = 0
MEMBER [Time].[1997].[Q1 / Q2] AS '[Time].[1997].Q1 / [Time].[1997].Q2',
SOLVE_ORDER = 1
SELECT … come prima
In assenza di SOLVE_ORDER si seguono ordini di valutazione prestabiliti
Nella definizione dei cubi: è sempre opportuno indicarlo esplicitamente.
42
Ordine di valutazione : membri addittivi
L’ordine di valutazione è irrilevante per membri addittivi
Esempio: Differenza del profitto tra i primi due trimestri del 1997
WITH MEMBER [Measures].[Store Profit] AS
'[Measures].[Store Sales] - [Measures].[Store Cost]’,
SOLVE_ORDER = 0
MEMBER [Time].[1997].[Q1 – Q2] AS '[Time].[1997].Q1 - [Time].[1997].Q2’,
SOLVE_ORDER = 1
SELECT
{([Measures].[Store Sales]), ([Measures].[Store Cost]),
([Measures].[Store Profit])} ON COLUMNS,
{([Time].[1997].Q1), ([Time].[1997].Q2),([Time].[1997].[Q1 – Q2])} ON ROWS
FROM [Sales]
Lo stesso risultato si ottiene invertendo l’ordine di valutazione!
43
Funzioni Numeriche
Sono funzioni (SUM,MAX,MIN, ..) applicate solitamente alle misure
SUM(«Set», «Expression»)
Calcola la somma di «Expression» su «Set»
Esempio: per ogni trimestre del 1997, totale delle vendite per gli stati OR e WA
WITH
MEMBER [Store].[OR + WA] AS
'SUM({[Store].[USA].[OR],[Store].[USA].[WA]},
[Measures].[Store Sales])'
SELECT
{([Store].[USA].[OR]), ([Store].[USA].[WA]),
([Store].[OR + WA])} ON COLUMNS,
{([Time].[1997].CHILDREN)} ON ROWS
FROM [Sales]
WHERE ([Measures].[Store Sales])
44
Funzioni Numeriche
L’insieme considerato nel calcolo delle funzioni numeriche è implicitamente
vincolato alle altre dimensioni usate nella interrogazione
SELECT {([Measures].[Store Sales]) } ON COLUMNS,
{([Store].[USA].CHILDREN)} ON ROWS
FROM [Sales]
WITH MEMBER [Measures].[Max1] AS
'MAX({[Store].[USA].CHILDREN},[Measures].[Store Sales])'
SELECT {([Measures].[Max1] ) } ON COLUMNS
FROM [Sales]
Se però aggiungo anche l’asse [Time].[1997].CHILDREN il massimo è riferito ai trimestri :
WITH MEMBER [Measures].[Max1] AS
'MAX({[Store].[USA].CHILDREN},[Measures].[Store Sales])'
SELECT [Time].[1997].CHILDREN ON COLUMNS,
[Store].[USA].CHILDREN ON ROWS
FROM [Sales]
WHERE [Measures].[Max1]
45
Funzioni Numeriche : esempio
Esempio:
per ogni trimestre del 1997, e per ogni stato degli USA
vendite e massimo delle vendite per gli stati degli USA
WITH MEMBER [Measures].[Max STATE OF USA Store Sales] AS
'MAX({[Store].[USA].CHILDREN},[Measures].[Store Sales])'
SELECT
CROSSJOIN(
{([Time].[1997].CHILDREN)},
{([Measures].[Store Sales]),
([Measures].[Max STATE OF USA Store Sales]) })
ON COLUMNS,
{([Store].[USA].CHILDREN)} ON ROWS
FROM [Sales]
46
Funzioni Numeriche : esempio
Un membro calcolato può essere usato nella definizione di un altro membro calcolato
Esempio: per ogni trimestre del 1997, e per ogni stato degli USA
vendite, massimo delle vendite e differenza per gli stati degli USA
WITH
MEMBER [Measures].[Max STATE OF USA Store Sales] AS
'MAX({[Store].[USA].CHILDREN},[Measures].[Store Sales])'
MEMBER [Measures].[Difference] AS
'[Measures].[Max STATE OF USA Store Sales] - [Measures].[Store Sales]’
SELECT
CROSSJOIN(
{([Time].[1997].CHILDREN)},
{([Measures].[Store Sales]), ([Measures].[Max STATE OF USA Store Sales]),
([Measures].[Difference])}) ON COLUMNS
{([Store].[USA].CHILDREN)} ON ROWS
FROM [Sales]
47
Misure Migliori e peggiori : TopCount
TopCount(«Set», «Count», «Numeric Expression»)
ordina un set in base al valore di «Numeric Expression»
e restituisce i primi «Count» membri, dove «Count» è un'espressione numerica.
SELECT TOPCOUNT ( [Product].[Product Name].MEMBERS,5,
( [Measures].[Unit Sales],[TIME].[1997])) ON COLUMNS
FROM SALES
Le vendite ([Measures].[Unit Sales]) per i trimestri del 1997
dei 5 prodotti più venduti nel 1997 (cioè rispetto a [Measures].[Unit Sales])
SELECT { ([TIME].[1997].CHILDREN)} ON COLUMNS,
TOPCOUNT ( [Product].[Product Name].MEMBERS,5,
( [Measures].[Unit Sales],[TIME].[1997])) ON ROWS FROM SALES
48
Misure Migliori e peggiori : TopSum
TopSum(«Set», «Value», «Num. Expr»)
ordina «Set» su «Num. Expr» e estrae i primi n (il più piccolo numero possibile)
elementi tali che la loro somma è almeno «Value».
SELECT
TOPSUM ( [Product].[Product Name].MEMBERS,1000,
[Measures].[Unit Sales]) ON COLUMNS
FROM SALES
WITH MEMBER [MEASURES].[NULLO] AS ' NULL '
SELECT
TOPSUM ( [Product].[Product Name].MEMBERS, 1000,
[Measures].[Unit Sales] ) ON COLUMNS
FROM SALES
WHERE [MEASURES].[NULLO]
49
Celle vuote
Le celle vuote sono presenti nelle istruzioni MDX quando i dati relativi
all'intersezione di due o più dimensioni non esistono.
La funzione IsEmpty(<expression>) restituisce TRUE se
<expression> è una cella vuota. In caso contrario, restituisce FALSE.
NON EMPTY : per non visualizzare le celle vuote
Quando il valore di cella vuota è un operando per uno degli operatori
numerici (+, -, *, /), ha la stessa funzione del valore zero.
Esempi
SELECT {([Store].[USA].CHILDREN)} ON COLUMNS,
{([Time].[Year].MEMBERS)} ON ROWS
FROM [Sales]
SELECT {([Store].[USA].CHILDREN)} ON COLUMNS,
NON EMPTY {([Time].[Year].MEMBERS)} ON ROWS
FROM [Sales]
WITH MEMBER [Time].[1997 - 1998]
AS '[Time].[1998] - [Time].[1997]'
SELECT {([Store].[USA].CHILDREN)} ON COLUMNS,
NON EMPTY {([Time].[1997 - 1998])} ON ROWS
FROM [Sales]
50
Operazioni sui membri
Alcune operatori consentono di accedere al membro “corrente” di una
dimensione e ai membri vicini di un dato membro
x.CURRENTMEMBER
– calcola il membro corrente della dimensione o livello x
m.PREVMEMBER e m.NEXTMEMBER
– calcola il membro che precede (segue) il membro m nell’ambito dello
stesso livello di m
– Per il primo membro PREVMEMBER restituisce una cella vuota
– Per l’ultimo membro NEXTMEMBER restituisce una cella vuota
Esempio
WITH MEMBER [Measures].[VENDITE TRIMESTRE PRECEDENTE] AS
'([Measures].[Store Sales], [Time].PREVMEMBER)'
SELECT
{ [Measures].[VENDITE TRIMESTRE PRECEDENTE]} ON COLUMNS,
{([Time].[1997].CHILDREN)} ON ROWS
FROM [Sales]
51
Operazioni sui membri: esempio
Esempio: calcolare, per ogni trimestre del 1997, gli incassi complessivi e la
differenza rispetto al trimestre precedente
WITH MEMBER [Measures].[Sales Difference] AS
'([Measures].[Store Sales], [Time].CURRENTMEMBER) ([Measures].[Store Sales], [Time].PREVMEMBER)'
SELECT
{([Measures].[Store Sales]),
([Measures].[Sales Difference])} ON COLUMNS,
{([Time].[1997].CHILDREN)} ON ROWS
FROM [Sales]
Si noti che il valore negativo viene indicato in modo particolare: dipende dal tipo di dato
Nota: il membro calcolato si può anche definire come
WITH MEMBER [Measures].[Sales Difference] AS
'[Measures].[Store Sales] - ([Measures].[Store Sales], [Time].PREVMEMBER)'
52
Serie temporali
Calcolo di valori cumulativi rispetto al tempo
Esempio: calcolare le vendite cumulative rispetto alla data
DATA
1/1/2004
3/1/2004
4/2/2004
5/2/2004
VENDITE
90
100
140
100
DATA
1/1/2004
3/1/2004
4/2/2004
5/2/2004
VENDITE CUMULATE
90
190
330
430
Per calcolare le vendite cumulate ad una certa data X (es. 4/2/2004) serve
una funzione che restituisca il set di tutte le date dell’anno precedenti o
uguali a tale data; tale funzione si chiama YTD:
YTD(X)
Le vendite cumulate alla data X si ottengono semplicemente con
SUM(YTD(X),[Measures].[Store Sales])
La funzione YTD è una caso particolare della funzione PeriodsToDate
53
Serie temporali : Funzione PeriodsToDate
PeriodsToDate([«Level»[, «Member»]])
– Nell'ambito di «Level» questa funzione restituisce il set di membri nel livello di
«Member», a partire dal primo membro fino a «Member».
– È quasi sempre usata per la dimensione Data, per la quale il risultato è molto intuitivo:
PeriodsToDate([Data].[Anno],
[Data].[Totale Data].[2000].[Quarter 4].[dicembre].[15])
PeriodsToDate([Data].[Mese],
[Data].[Totale Data].[2000].[Quarter 4].[dicembre].[15])
Nota: L’esempio è riferito al cubo dei biglietti
54
Serie temporali : Funzione PeriodsToDate
PeriodsToDate([«Level»[, «Member»]])
– Sia L_Member il livello di Member;
– Siano Member_1, Member_2, …., Member_N i membri di L_Member; si suppone che essi costituiscano una
sequenza, ovvero che siano ordinati, quindi si può stabilire che Member_i precede Member_j
– Sia M_Level il membro a livello Level padre (ancestor) del membro Member
– La funzione restituisce tutti i discendenti di M_Level a livello L_Member che precedono o sono uguali a Member
– Se i membri di L_Member non sono ordinati, la funzione restituisce tutti i discendenti di M_Level a livello
L_Member
STORE
CITY
STATE
COUNTRY
(ALL)
Ditutto
RE
EmiliaR
Italia
ALL
NonSoloX
RE
EmiliaR
Italia
ALL
NonSoloY
MO
EmiliaR
Italia
ALL
NonSoloZ
RM
Lazio
Italia
ALL
...
...
...
...
ALL
PeriodsToDate([COUNTRY],[RE] ) = { MO,RE,RM}
PeriodsToDate([STATE],[RE] ) = { MO,RE }
55
Serie temporali : Funzione PeriodsToDate
PeriodsToDate([«Level»[, «Member»]])
–
Se non si specifica un livello o un membro, il valore di «Member» sarà Time.CurrentMember e
«Level» sarà il livello padre di Time.CurrentMember.
WITH
MEMBER
[Measures].[INCASSOTOTALEDAINIZIOMESE] AS
'SUM(PeriodsToDate([Data].[Mese]),[Measures].[Incasso])'
MEMBER
[Measures].[INCASSOTOTALEDAINIZIOANNO] AS
'SUM(PeriodsToDate([Data].[Anno]),[Measures].[Incasso])'
SELECT {[Measures].[Incasso],
[Measures].[INCASSOTOTALEDAINIZIOMESE],
[Measures].[INCASSOTOTALEDAINIZIOANNO] } ON COLUMNS,
[Data].[Totale Data].[2000].[Quarter 4].[novembre].CHILDREN ON ROWS
FROM BIGLIETTI
Nota: L’esempio è riferito al cubo dei biglietti
56
Serie temporali : Funzione YTD
PeriodsToDate([«Level»[, «Member»]])
– Se si specifica solo il livello, «Member» sarà dimension.CurrentMember,
dove dimension è la dimensione di «Level».
Ytd(«Member»)
corrisponde a PeriodsToDate(Year, «Member»).
YTD([Data].[Totale Data].[2000].[Quarter 4].[dicembre].[15])
Ytd()
corrisponde a PeriodsToDate(Year) e quindi il valore di «Member»
è sarà Time.CurrentMember
57
Serie Temporali: Funzione YTD - esempi
Esempio: vendite del 1997 per trimestre e vendite cumulate rispetto all’anno
WITH MEMBER [Measures].[ACCUMULATED SALES] AS
'SUM(YTD(),[Measures].[Store Sales])'
SELECT {[Measures].[Store Sales], [Measures].[ACCUMULATED SALES] } ON
COLUMNS,
{ [TIME].[1997].CHILDREN} ON ROWS
FROM SALES
Esempio: vendite del 1997 per mese e vendite cumulate rispetto all’anno
WITH MEMBER [MEASURES].[VENDITE ACCUMULATE]
AS 'SUM(YTD(),[MEASURES].[STORE SALES])'
SELECT
{[MEASURES].[STORE SALES],
[MEASURES].[VENDITE ACCUMULATE] } ON COLUMNS,
{DESCENDANTS([TIME].[1997],[TIME].[MONTH])}
ON ROWS FROM SALES
58
Serie Temporali: Funzione YTD - esempi
Esempio:
vendite del 1997 per mese e vendite cumulate
rispetto al trimestre e rispetto all’anno
WITH MEMBER
[MEASURES].[VENDITE ACCUMULATE PER ANNO]
AS 'SUM(PERIODSTODATE (YEAR), [MEASURES].[STORE SALES])'
MEMBER [MEASURES].[VENDITE ACCUMULATE PER TRIMESTRE]
AS 'SUM(PERIODSTODATE (QUARTER), [MEASURES].[STORE SALES])'
SELECT
{[MEASURES].[STORE SALES], [MEASURES].[VENDITE ACCUMULATE PER TRIMESTRE],
[MEASURES]. [VENDITE ACCUMULATE PER ANNO] } ON COLUMNS,
{DESCENDANTS([TIME].[1997],[TIME].[MONTH])} ON ROWS
FROM SALES
59