DAX e le Measure, Cosa Sono e Come si Usano
Potrebbe interessarti:
Se vuoi imparare a preparare, modellare, visualizzare e analizzare i dati aziendali in modo efficace, dai un’occhiata al corso Introduzione a Power BI, e al Corso Avanzato Power BI DAX.
Cos’è una Measure (Misura)
Nel contesto dei Data Warehouse e della modellazione dimensionale, il termine Measure (Misura) indica un valore numerico di interesse aziendale, ovvero un’informazione quantitativa che può essere conteggiata, aggregata o utilizzata in calcoli. In Power BI, le Misure sono espressioni DAX che restituiscono un valore scalare — tipicamente un numero, ma anche una stringa o un valore booleano — e vengono sempre calcolate in base al Filter Context. Il Filter Context rappresenta l’insieme dei filtri applicati a un visual o a una pagina del report (come selezioni dell’utente, slicer, filtri di pagina, relazioni e contesto di riga generato da tabelle o matrici), ed è ciò che determina il risultato finale della misura.
Le Misure si creano premendo il pulsante “New measure” nel tab “Home”, “Table tools” o “Measure tool”:


e rispettano la seguente sintassi:
Measure Name = <DAX expression>
Vengono utilizzate per eseguire calcoli di aggregazione sui dati,
come somma, media, valore minimo, valore massimo, conteggio,
oppure per implementare logiche più avanzate tramite funzioni DAX complesse.
Ad esempio, nella tabella Sales possiamo creare una misura che calcoli il totale delle vendite
considerando tutte le righe filtrate nel contesto corrente:
Total Sales =
SUM(Sales[Sales Amount])
oppure:
Total Sales =
SUMX(
Sales,
Sales[Product Cost] * Sales[Order Quantity]
)
Un modo utile per comprenderle è pensare alle Misure come calcoli eseguiti a livello di report: il loro valore viene ricalcolato dinamicamente in base ai filtri applicati dall’utente a un dato visual. Questo le distingue dalle Calculated Column, che invece producono calcoli a livello di riga, valutati una volta sola durante il processo di refresh dei dati. Le Misure non sono elementi statici: esse vengono calcolate in tempo reale all’interno del Filter Context corrente di un report, e il loro risultato cambia in base ai filtri attivi in quel momento.
Nell’interfaccia di Power BI Desktop, nella sezione “Fields”, le Misure sono riconoscibili grazie a un’icona a forma di calcolatrice:

Poiché non creano alcuna colonna fisica all’interno delle tabelle del modello, non sono visualizzabili né ispezionabili nella Data View: esistono solo come definizioni DAX associate al modello e vengono valutate solo quando necessario.
Differenze tra Measure e Calculated Column
Come abbiamo già visto, una Calculated Column crea una colonna fisica nel modello che occupa memoria, è statica (non cambia in base ai filtri del report), ritorna un valore per ogni riga della tabella, e viene calcolata:
- durante la sua fase di definzione,
- e in ogni fase di refresh dei dati.
Lo scopo fondamentale di una Calculated Column è integrare la tabella con nuovi dati utili all’analisi o alle relazioni, che devono essere presenti per ogni riga, rimanere persistenti, poter essere filtrati o ordinati, oppure fungere da chiavi nel modello.
Di contro, una Misura viene calcolata dinamicamente al momento della visualizzazione, in base al Filter Context. Essa non crea colonne fisiche, ma restituisce un singolo valore scalare (es: totale vendite, media, percentuale, ecc.). Quindi, oltre alla sua definizione, essa non occupa altro spazio in memoria, perché non materializza dati. Il risultato del calcolo di una Misura è dinamico, e cambia in base ai filtri del report. Possiamo usare una Misura quando dobbiamo fare un calcolo aggregato, dinamico o contestuale, per esempio:
- somma delle vendite filtrata dall’utente
- percentuali rispetto ad un totale
- KPI dinamici
- calcoli basati su contesti complessi (Time Intelligence: YTD, MTD, YoY…)
- confronti tra aggregati
In sintesi:
La Calculated Column lavora “prima del report”, mentre la Measure lavora “durante il report”. La prima arricchisce la tabella, la seconda calcola quando serve, “a valle” del Filter Context.
Alcuni Esempi di Measure
Vediamo ora alcuni esempi di misure elementari, la cui sintassi ricorda quella delle colonne calcolate. Per affrontare esempi più avanzati, però, sarà necessario introdurre prima i concetti di contesto di valutazione, in particolare Filter Context e Row Context, e comprendere come questi influenzino il modo in cui una misura viene calcolata all’interno di Power BI. Solo dopo aver chiarito il ruolo dei contesti potremo analizzare in dettaglio la valutazione di misure più articolate.
Supponiamo di voler creare una Misura che calcoli il totale della colonna [Total Product Cost] per l’intero dataset.
In questo caso, possiamo definire la seguente espressione DAX
(la Misura deve sempre essere creata tramite il pulsante “New measure”):
// Calculate the sum of the Total Product Cost amount within the current Flter Context
Total Cost = SUM(Sales[Total Product Cost])
Possiamo calcolare il profitto (ricavi - costi) in questo modo:
Profit = SUM(Sales[Sales Amount]) - SUM(Sales[Total Product Cost])
Ricordiamoci che il vantaggio di una Misura è che il suo codice può chiamare un’altra Measure.
Pertanto, possiamo calcolare il valore di Profit riutilizzando le Measure Total Sales
e Total Cost già create nel Data Model:
// reusing the previously created "Total Sales" and "Total Cost" Measure
Profit = [Total Sales] - [Total Cost]
Possiamo calcolare il margine di profitto in questo modo. In questo caso, per formattare correttamente i valori ritornati da questa misura, dobbiamo andare nel tab “Measure tools” e cambia la formattazione in percentuale (%):
// Profit Margin = Profit / Revenue * 100
Profit Margin = DIVIDE([Profit], [Total Sales])
Measure Implicite ed Esplicite
Una Measure implicita è una misura creata automaticamente da Power BI,
senza che l’utente scriva alcuna formula DAX.
Le Misure implicite vengono generate automaticamente quando un campo con datatype numerico
viene trascinato in un visual. In questo caso, Power BI applica un’aggregazione predefinita,
di solito la sommatoria (sum).
Ad esempio, nelle immagini seguenti, il campo numerico Total Product Cost
viene selezionato per configurare un visual di tipo Column Chart (si veda la proprietà Y-axis),
che calcola la sommatoria dei costi (dato aggregato) per anno e trimestre:


Tuttavia, è considerata una buona pratica creare Misure esplicite invece di affidarsi a quelle implicite. L’utilizzo di misure definite manualmente in DAX offre infatti diversi vantaggi:
- le misure possono essere costruite sulla base di altre misure, favorendo riuso e modularità del codice;
- permettono di incapsulare la logica in un unico punto, rendendo più semplice la manutenzione;
- consentono di centralizzare la formattazione numerica, così da mantenere una presentazione coerente;
- le misure esplicite sono indipendenti dalla tabella in cui vengono create: possono essere spostate liberamente in un’altra tabella senza influire sul loro funzionamento.
I Contesti di Valutazione
Filter Context
Il Filter Context determina quali righe delle tabelle del modello dati sono disponibili per essere utilizzate da un visual o da una misura. È formato dall’insieme di tutti i filtri attivi in un dato momento: selezioni effettuate in tabelle o matrici, filtri di pagina o di report, slicer, interazioni tra visual e qualsiasi altro elemento che restringe il set di dati visibile.
Il Filter Context si propaga automaticamente da una tabella all’altra attraverso le relazioni del modello, rispettando la direzione di propagazione definita dal parametro Cross-Filter Direction.
Le Measure vengono sempre valutate all’interno del Filter Context del visual in cui sono utilizzate: il loro risultato dipende quindi dai filtri attivi e dalle interazioni dell’utente nel report. Le Calculated Column, invece, vengono calcolate solo al momento della loro creazione o durante il refresh del dataset. Per questo motivo non hanno accesso al Filter Context, e il loro valore rimane stabile, indipendente dai filtri applicati nel report.
Row Context
Il Row Context è un contesto di valutazione che rappresenta il riferimento alla riga corrente di una tabella del modello dati. Indica a DAX quale riga considerare quando occorre recuperare il valore di una colonna per eseguire un calcolo. A differenza del Filter Context, il Row Context non si propaga automaticamente attraverso le relazioni del modello. Per accedere ai valori di tabelle correlate partendo da un Row Context esistente, è necessario usare in modo esplicito le funzioni DAX RELATED o RELATEDTABLE.
Quando si definisce una Calculated Column, Power BI crea automaticamente un Row Context implicito:
DAX sa che deve eseguire il calcolo una riga alla volta, e valuta l’espressione per ogni record della tabella.
Nell’esempio seguente, DAX moltiplica Sales[Quantity] per Sales[Net Price] per ciascuna riga,
producendo il risultato corretto grazie al Row Context implicito fornito durante la creazione della colonna calcolata:
// Calculated Column:
// Power BI implicitly provides the Row Context for you
Amount = Sales[Quantity] * Sales[Unit Price]
A differenza delle Calculated Column, le Measure non dispongono di un Row Context implicito. Senza un Row Context non è possibile accedere direttamente ai valori delle colonne riga per riga.
Per ovviare a questo limite, DAX mette a disposizione una serie di funzioni note come “funzioni di iterazione” (o iterator function). Queste funzioni lavorano creando internamente un meccanismo di iterazione che esamina ogni riga di una tabella e, per ciascuna di esse:
- generano un nuovo Row Context, cioè un riferimento alla riga corrente;
- valutano un’espressione DAX utilizzando quel Row Context, memorizzando il risultato in una struttura temporanea.
Al termine dell’iterazione, la funzione raccoglie tutti i valori prodotti al punto (2) e li aggrega in un unico risultato (somma, media, conteggio, ecc.), restituendo così un valore scalare utilizzabile dalla misura.
Calcolo di una Measure
Le Measure in Power BI vengono calcolate attraverso un processo articolato in quattro fasi principali, che determinano il contesto in cui la formula DAX viene valutata e, di conseguenza, il risultato finale.
Definizione del Filter Context iniziale:
Per prima cosa viene individuato il Filter Context attivo. Questo insieme di filtri deriva da tutti gli elementi che influenzano il report:- filtri a livello di Report, Pagina e Visual;
- filtri di Drill-through;
- selezioni effettuate su Slicer;
- filtri impliciti derivanti dalle righe e colonne presenti in tabelle e matrici;
- interazioni provenienti da altri visual (ad esempio il cross-filtering in seguito a un clic su un grafico).
L’unione di tutti questi elementi definisce quali righe del modello dati sono potenzialmente visibili alla misura prima di qualsiasi modifica successiva.
Esecuzione delle modifiche al Filter Context da parte delle formule DAX:
Nella seconda fase, eventuali funzioni DAX in grado di alterare il Filter Context — in particolare le funzioni CALCULATE e CALCULATETABLE — possono aggiungere nuovi filtri, sostituire o rimuovere filtri esistenti.Propagazione del Filter Context tramite le relazioni:
Successivamente, il Filter Context risultante viene propagato automaticamente ad altre tabelle del datamodel attraverso le relazioni. Il modo in cui il filtro “viaggia” è determinato dall’attributo Cross-filter direction della relazione:- “single direction”: il filtro scorre solo da una tabella all’altra;
- “both directions”: il filtro si propaga in entrambe le direzioni.
Questa propagazione è fondamentale, perché consente a una misura calcolata in una tabella di riflettere correttamente i dati collegati.
Esecuzione del calcolo della Measure:
Infine, con il Filter Context definitivo, vengono determinate le righe attive del data model, e la misura valuta la propria logica su questi dati filtrati. Il risultato mostrato nel visual rappresenta quindi l’applicazione della formula DAX all’insieme di righe che rispettano i criteri imposti da tutti i filtri, diretti o indiretti.
Le Funzioni di Iterazione
Una funzione di iterazione è una funzione DAX che scorre riga per riga una tabella, crea per ciascuna riga un Row Context, valuta un’espressione fornita dall’utente, e poi aggrega tutti i risultati ottenuti.
Una delle funzioni di iterazione più famose è SUMX, la quale scorre una tabella riga per riga, calcola un’espressione per ciascuna riga, e poi somma i risultati ottenuti. Ad esempio:
// Measure
Sales Amount =
SUMX(
// the table containing the rows for which the expression will be evaluated
Sales,
// the expression to be evaluated for each row of the table
Sales[Quantity] * Sales[Unit Price]
)
Nell’esempio precedente, la funzione SUMX considera la tabella Sales indicata dal primo parametro,
ed esegue le seguenti operazioni:
- itera su tale tabella, ovvero la scorre riga per riga;
- per ogni singolo record crea un nuovo Row Context, che rappresenta la referenza a tale riga, o “la coordinata y” che ci permette di prendere i valori di cella referenziati dall’espressione DAX;
- calcola l’espressione indicata come secondo parametro (
Sales[Quantity] * Sales[Unit Price]), e salva il risultato in memoria; - alla fine del ciclo, somma tutti i risultati intermedi ottenuti al punto (3), e ritorna tale valore aggregato.
È importante ricordare che il Row Context fornisce un riferimento solo alle colonne della tabella su cui si sta iterando.
Ciò significa che, se l’iterazione avviene sulla Fact Table Sales,
il Row Context permette di accedere esclusivamente ai valori delle colonne di Sales.
Non è invece possibile richiamare direttamente le colonne della Dimension Table Product,
perché il Row Context non si estende automaticamente alle tabelle correlate.
Questo comportamento vale sia per le Measure, che per le
Calculated Column.
Per raggiungere una tabella diversa da quella in iterazione è necessario utilizzare funzioni specifiche come RELATED o RELATEDTABLE, che consentono di attraversare le relazioni in modo esplicito. Consideriamo il data model seguente, e focalizziamoci sulle tabelle ‘Winesales’ e ‘Wines’:

Visto che il campo [PRICE PER CASE] è sulla tabella Wines,
e il campo [CASES SOLD] è sulla tabella Winesales,
per calcolare Total Sales Measure partendo da quest’ultima tabella,
devo usare un’espressione del tipo:
// Measure
Total Sales Measure =
// iterator function -> row context
SUMX(
// source table
Winesales,
// the expression to be evaluated for each row of the source table.
// Note the mandatory usage of RELATED function to access to the fields of 'Wines' table
// associated with the current 'Winesales' record
Winesales[CASES SOLD] * RELATED(Wines[PRICE PER CASE])
)
In questo esempio, per ogni iterazione sulla tabella Winesales (posta sul lato “Molti” della relazione),
la funzione RELATED usata nell’espressione del secondo parametro serve per raggiungere il corrispondente record
della tabella Wines (posta sul lato “Uno” della relazione).
Se volessi partire dalla tabella Wines, posta sul lato “Molti” della relazione,
dovrei usare una misura come questa:
// Measure
Wines Total Sales Measure =
SUMX(
Wines,
[PRICE PER CASE] * SUMX(RELATEDTABLE(Winesales), Winesales[CASES SOLD])
)
In questo secondo esempio, per ogni iterazione sulla tabella Wines,
la funzione RELATEDTABLE ritorna il gruppo di record di Winesales che sono in relazione con il vino corrente.
La seconda chiamata a SUMX serve per aggregare i valori [CASES SOLD] delle vendite effettuate per tale vino.
Altre funzioni della “famiglia X” sono: AVERAGEX,
MINX, MAXX, COUNTX,
COUNTAX e PRODUCTX.
Ad esempio, per calcolare il prezzo medio dei vini, possiamo usare questa Misura:
// Measure
Average Price =
AVERAGEX (
Winesales,
RELATED(Wines[PRICE PER CASE])
)
Per calcolare il prezzo massimo:
// Measure
Max Price =
MAXX(
Winesales,
RELATED(Wines[PRICE PER CASE])
)
Assegnazione delle Measure
A differenza delle Calculated Column, le Misure non richiedono di essere collocate in una tabella specifica per poter funzionare: il loro risultato dipende esclusivamente dal contesto di valutazione, non dalla tabella a cui appartengono. È comunque buona pratica assegnare ogni misura alla tabella in cui ha più senso dal punto di vista logico e funzionale. Questo rende il modello più leggibile, facilita la manutenzione e permette di individuare rapidamente le misure rilevanti per una determinata entità del data model.
Se una misura è stata inserita nella tabella “sbagliata”, è possibile spostarla facilmente verso una tabella più appropriata utilizzando il comando Measure tools / Structure / Home table nella Data View. Questo spostamento non modifica in alcun modo il comportamento della misura, ma contribuisce a mantenere ordinata e chiara la struttura del modello:

Tabelle di Measure
Le Misure possono essere collocate nella tabella a cui appartengono logicamente, così da mantenere il modello chiaro e coerente. In alternativa, è possibile creare una o più tabelle dedicate alle Misure, utilizzate esclusivamente come contenitori organizzativi per tutti gli oggetti di tipo Measure. Questa scelta può migliorare la leggibilità del modello, soprattutto in progetti complessi. Per creare una tabella di sole Misure, puoi procedere così:
crea una nuova tabella vuota tramite il pulsante “Enter Data”. Power BI genererà automaticamente una tabella contenente una sola colonna e una singola riga;
aggiungi le Misure direttamente a questa tabella, oppure utilizza il pannello “Measure tools” per spostare nella nuova tabella le Misure già esistenti presenti in altre tabelle;
una volta che la tabella contiene solo Misure, elimina la colonna creata automaticamente al punto (1), poiché non serve allo scopo, e la tabella può rimanere senza colonne fisiche:

La tabella creata al punto (1) assumerà l’icona di una “Measure Table” e verrà spostata all’inizio dell’elenco delle Query:

Measure e la Funzione Calculate
Le Misure permettono di ottenere risultati utili, ma il loro potenziale rimane parzialmente limitato senza l’uso della funzione CALCULATE. Tale funzione consente infatti di modificare programmaticamente il Filter Context in cui una misura viene valutata, rendendo possibile applicare logiche avanzate come ad esempio confronti temporali e filtri condizionali. Se sei interessato, leggi il post “DAX e La Funzione Calculate”.