DAX e La Funzione CALCULATE

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.

Dimmi di Più

Le funzioni DAX CALCULATE e CALCULATETABLE sono usate per valutare un’espressione DAX in un Filter Context modificato, dove tale modifica viene effettuata programmaticamente (tramite codice).

La Funzione CALCULATE, Sintassi e Utilizzo

CALCULATE è la funzione più importante in DAX. Essa prende un’espressione o una Misura, e la valuta in un Filter Context modificato rispetto al Filter Context generato dai filtri attivi provenienti dal Visual, dagli Slicer o dal riquadro dei filtri. Essa ha la seguente sintassi:

CALCULATE(expression, filter1, filter2, ..., filterN)

dove:

  • expression:
    l’espressione da valutare nel Filter Context modificato dai parametri di filtro filter1…n

  • filter1…n:
    le espressioni booleane facoltative o espressioni di tabella utilizzate per aggiornare il Filter Context. Quando vengono specificati più parametri di filtro, la funzione li unisce utilizzando l’operatore logico AND.

Quando un’espressione DAX utilizza la funzione CALCULATE, i parametri di filtro vengono valutati, e il loro risultato viene utilizzato per aggiornare o modificare il Filter Context. Successivamente, CALCULATE valuta l’espressione utilizzando il Filter Context modificato. Ma questo cosa vuol dire, in pratica?

Il Filter Context è l’insieme dei filtri attivi in un certo momento: filtri applicati dall’utente (slicer, segmentazioni, selezioni di visual), filtri di pagina, filtri di report e filtri derivati dalle relazioni del modello. Quando usiamo CALCULATE, la funzione prende il Filter Context esistente e lo cambia secondo le istruzioni che gli diamo. In altre parole: CALCULATE parte dai filtri già attivi, e successivamente aggiunge, sostituisce o rimuove i filtri specificati dai parametri filter1...n. Alla fine di tale processo, Power BI valuta l’espressione definita dal parametro expression nel nuovo contesto risultante. E’ importante notare che i filtri definiti da CALCULATE sovrascrivono eventuali filtri impostati dall’utente sugli stessi campi.

Ad esempio, confrontiamo il comportamento di due Misure: All Sales, che si limita a calcolare le vendite totali, e Red Sales, che restituisce le vendite totali relative ai prodotti di colore rosso:

// Measure
All Sales =
    SUMX(
        // the Sales Table to iterate through, row by row
        Sales,

        // the expression to compute for each row
        Sales[Order Quantity] * Sales[Unit Price]
    )

// Measure:
// CALCULATE evaluates the SUMX expression in a modified Filter Context.
// In this case, it computes the Sales Amount only for Sales records
// associated with Products records whose color is "Red".
Red Sales = CALCULATE(

    // returns the sum of the "Sales Amounts" expression
    // evaluated for each Sales in the Sales Table
    SUMX(

        // the Sales Table to iterate through, row by row
        Sales,

        // the expression to compute for each row
        Sales[Order Quantity] * Sales[Unit Price]
    ),

    // boolean filter expression:
    // only consider the Sales records associated with
    // Products records whose color is "Red"
    'Product'[Color] = "Red"
)

Il grafico risultante, che confronta i valori delle due Measure All Sales e Red Sales raggruppati per Anno Fiscale è il seguente:

Uso della funzione DAX 'CALCULATE'
Figura 1: Uso della funzione DAX ‘CALCULATE’

Consideriamo ora il data model “Winesales”, già visto nel post sulle Misure:

Diagramma del Data Model 'Winesales'
Figura 2: Data Model ‘Winesales’

Per ciascuno dei nostri vini, vorremmo calcolare la percentuale di Total Cases vendute nel 2025 rispetto al valore Total Cases aggregato per tutti gli anni. Nel Data Model, la Dimension Table DateTable che è correlata alla Fact Table Winesales tramite le colonne DateTable[DATEKEY] e Winesales[SALE DATE]. Se filtriamo DateTable[YEAR], il filtro si propagherà a Winesales per filtrare le vendite di quell’anno. Possiamo utilizzare la funzione CALCULATE come segue:

// Measure:
// calculate the Wines' total sales
Total Cases =
    SUMX(
        Winesales,
        Winesales[CASES SOLD]
    )

// Measure:
// calculate the Wines' total sales for year 2025
Total Cases 2025 =
    CALCULATE(
        [Total Cases],             // MEASURE to calculate
        DateTable[YEAR] = 2025     // filter expression
    )

// Measure:
// calculate the ratio between "Total Cases 2025" and "Total Cases"
Total Cases 2025 % =
    DIVIDE(
        [Total Cases 2025],        // numerator
        CALCULATE(                 // denominator: consider all the sales' years
            [Total Cases],
            ALL(DateTable[YEAR])
        )
    )

La Misura Total Cases 2025 calcola le vendite per l’anno 2025, mentre Total Cases 2025 % calcola le relative vendite percentuali. In tale misura, il denominatore considera tutti gli anni di vendita, indipendentemente da eventuali filtri impostati dall’utente nella reportistica, su un dato visual. Il risultato è il seguente:

Esempi di uso delle Misure 'Total Cases'
Figura 3: Esempi di uso delle Misure ‘Total Cases’

Filtri Booleani e Tabellari

In relazione ai parametri opzionali di filtro, essi possono essere di due tipi:

  • Filtri Booleani:
    Un filtro booleano è un’espressione che restituisce TRUE / FALSE per ogni riga. Power BI mantiene nel contesto solo le righe per cui l’espressione è TRUE. Ecco un’esempio di condizione booleana:

    'Region'[Region] = "Italia"
    
  • Filtri Tabellari:
    Un filtro tabellare è una tabella che viene passata a CALCULATE. Power BI filtra il modello usando tutte le righe e le colonne presenti nella tabella. Ecco un’esempio di filtro tabellare:

    ALL(Sales)
    

Uso di Filtri Multipli

La funzione CALCULATE accetta più argomenti di filtro, che vengono combinati assieme tramite l’operatore logico AND:

// Measure
Total Cases in Nov 2025 =
    CALCULATE(
        [Total Cases],                            // Expression / Measure
        DateTable[YEAR] = 2025,                   // filter 1
        DateTable[MONTH] = "Nov"                  // filter 2
    )

// Measure
Total Cases for Mario in Italy =
    CALCULATE(
        [Total Cases],                            // Expression / Measure
        SalesPeople[SALESPERSON] = "Mario Rossi", // filter 1
        Regions[REGION] = "Italy"                 // filter 2
    )

// Measure
Average Cases for Acme LLC in 2025 =
    CALCULATE(
        AVERAGE(Winesales[CASES SOLD]),           // Expression / Measure
        DateTable[Year] = 2025,                   // filter 1
        Customers[CUSTOMER NAME] = "Acme LLC"     // filter 2
    )

Per utilizzare l’operatore logico OR sulla stessa colonna, è possibile utilizzare l’operatore doppio pipe || all’interno dello stesso argomento filtro:

// Measure
Total Cases 2024 or 2025 =
    CALCULATE (
        [Total Cases],                     // Expression
        DateTable[YEAR] = 2025 ||          // OR filter
            DateTable[YEAR] = 2024
    )

// Measure
Average Cases Italy or France =
    CALCULATE(
        AVERAGE(Winesales[CASES SOLD]),    // Expression
        Regions[REGION] = "italy" ||       // OR filter
            Regions[REGION] = "france"
    )

E’ anche possibile utilizzare CALCULATE, assieme alla funzione tabellare ALL, per ignorare i filtri attuali applicati al Filter Context dall’utente. Ad esempio:

// count the number of rows in "Sales" Table,
// ignoring any filter applied to 'Product' and 'Sales Territory' tables.
Sales Row Count = CALCULATE(

    // expression: count the number of rows in "Sales" Table
    COUNTROWS(Sales),

    // filter1:
    // consider ALL the rows of "Product" Table
    ALL('Product'),

    // filter2:
    // consider ALL the rows of "Sales Territory" Table
    ALL('Sales Territory')
)

CALCULATE nelle Calculated Column

Oltre che nelle Misure, possiamo anche usare CALCULATE nelle Calculated Column. Nella tabella Winesales, possiamo calcolare un Running Total (la somma dei valori dall’inizio di un periodo fino al momento attuale) dei valori CASES SOLD utilizzando la seguente colonna calcolata:

 1// Winesales's Calculated Column
 2CUMULATIVE CASES SOLD =
 3    // "SALE DATE" for current Winesales
 4    VAR curDate = Winesales[SALE DATE]
 5
 6    // get a table with all the Winesales records
 7    // having date <= current winesale's date
 8    VAR wineSalesUntilCurrentRow =
 9        FILTER(
10            Winesales,
11            Winesales[SALE DATE] <= curDate)
12
13    // compute the sum of CASES SOLD considering all the records
14    // of "wineSalesUntilCurrentRow" table
15    VAR val =
16        CALCULATE(
17            SUM(Winesales[CASES SOLD]),
18            wineSalesUntilCurrentRow
19        )
20
21    RETURN val

L’espressione CUMULATIVE CASES SOLD viene eseguita riga per riga. In particolare:

  • a linea 8-9, La funzione FILTER ritorna una tabella temporanea con tutti i record di Winesales che hanno data data di vendita minore o uguale alla data del record corrente. Il risultato viene salvato nella variabile wineSalesUntilCurrentRow.

  • a linea 16 viene usata la funzione CALCULATE, che valuta la sommatoria di casse di vino vendute, considerando solo i record salvati nella tabella referenziata da wineSalesUntilCurrentRow.

Il risultato è il seguente:

Uso di CALCULATE in una Calculated Column
Figura 4: Uso di CALCULATE in una Calculated Column

La Funzione CALCULATETABLE

Similmanete a CALCULATE per i valori scalari, la funzione CALCULATETABLE viene utilizzata per modificare il Filter Context per calcolare espressioni che restituiscono tabelle. Ad esempio, la seguente espressione restituisce una tabella calcolata (una tabella generata da un’espressione DAX) con:

  1. tutte le colonne della tabella Product;
  2. solo le righe relative alle condizioni dei due parametri di filtro, ovvero solo prodotti con categoria “Bikes”, e il cui nome inizia con “Touring-3000”.

Ricordiamoci che le due condizioni di filtro sono legate assieme con l’operatore AND logico:

// "CalcProduct" Calculated Table:
// CALCULATETABLE evaluates a table expression
// in a Filter Context modified by its filter parameters.
// In this case, it returns a Table containing all the records of the Product table
// where "Product Category" is "Bikes" and "English Product Name" starts with "Touring-3000".
CalcProduct = CALCULATETABLE(

      // the table expression to be evaluated
      'Product',

      // filter1:
      // consider only the "Bikes" Category
      'Product'[Product Category] = "Bikes",

      // filter2:
      // consider only Products having Name starting with "Touring-3000"
      LEFT('Product'[English Product Name], 12) = "Touring-3000"
  )

Il risultato della tabella ritornata da una funzione tabellare come CALCULATETABLE può essere utilizzato come parametro di input per un’altra funzione tabellare, come FILTER, oppure come parametro di filtro per la funzione CALCULATE. Ad esempio:

// Measure
Sales Active Customers 2024 =
    CALCULATE(
        // the expression to calculate
        [Total Sales],

        // table filter:
        // returns all the active customers acquired in 2024, or earlier
        CALCULATETABLE(
            'Customers',
            'Customers'[IsActive] = TRUE(),
            YEAR('Customers'[StartDate]) <= 2024
        )
    )