DAX e La Funzione ALL

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ù

Sintassi di ALL

In DAX, la funzione ALL restituisce tutte le righe di una tabella, oppure tutti i valori distinti di una o più colonne, ignorando i filtri che potrebbero essere presenti nel Filter Context corrente. La funzione viene tipicamente utilizzata per rimuovere o ridefinire i filtri applicati a una parte del modello dati, ed è fondamentale per costruire misure come percentuali sul totale, confronti con aggregazioni globali o analisi indipendenti dal contesto di selezione. La sintassi generale di ALL è la seguente:

= ALL(TableNameOrColumnName, ColumnName1, ..., ColumnNamN)
ParametroDescrizione
TableNameOrColumnNamela tabella o la colonna da cui si desidera rimuovere i filtri (opzionale).
ColumnName1…NUna o più colonne specifiche da cui si desidera cancellare i filtri (opzionale).

Ad esempio:

// count the number of wines in the Wines table,
// ignoring any applied filter on that table
= COUNTROWS(
      // generate a virtual table containing all the rows of the Wines table
      ALL(Wines)
  )

In questo caso, ALL(Wines) genera una tabella virtuale che contiene tutte le righe della tabella Wines, indipendentemente da slicer, filtri di pagina o filtri applicati da altri visual. Di conseguenza, la funzione COUNTROWS restituisce sempre il numero totale di vini presenti nella tabella.

La funzione ALL, chiamata senza argomenti può essere utilizzato solo come modificatore di CALCULATE o CALCULATETABLE, e rimuove tutti i filtri dal Filter Context corrente. Ad esempio:

Total No. of Sales =
    CALCULATE(
        // expression to calculate
        COUNTROWS(Winesales),

        // removes all the filters from the Filter Context
        ALL()
    )

Per facilitare la comprensione del comportamento di ALL, prenderemo questi tre diversi oggetti da cui tale funzione può rimuovere i filtri, e li esploreremo separatamente, come segue:

  1. Fact Table
  2. Dimension Table
  3. Table Column

ALL Sulle Fact Table

Quando la funzione ALL viene applicata a una Fact Table, essa rimuove i filtri diretti su quella tabella, ma non elimina quelli provenienti dalle Dimension Table collegate. In altre parole, ALL azzera il Filter Context esclusivamente sulla Fact Table, senza neutralizzare i filtri propagati dalle tabelle dimensionali. In questo modo, una misura calcolata sulla Fact Table viene valutata su tutte le righe della tabella dei fatti, indipendentemente dai filtri applicati direttamente su di essa. Questo comportamento è particolarmente utile per calcolare totali generali, valori di riferimento globali o percentuali rispetto al totale complessivo. Consideriamo un Visual di tipo Table che mostra le seguenti Misure:

// Measure
No. Of Sales = COUNTROWS(Winesales)

// Measure
Grand Total No. of Sales = COUNTROWS(ALL(Winesales))

// Measure
No. of Sales as Percent of Grand Total =
    DIVIDE(
        [No. of Sales],             // nominator
        [Grand Total No. of Sales]  // denominator
    )

La misura No. Of Sales conta il numero di righe della Fact Table Winesales nel Filter Context corrente, quindi risente dei filtri applicati alle dimensioni (ad esempio tipo di vino, paese, venditore, ecc.). Al contrario, nella misura Grand Total No. of Sales dobbiamo ignorare i filtri provenienti dalla Dimension Table Wines (e da qualsiasi altra dimensione), in modo da calcolare il numero totale di vendite per tutti i vini, pari a 2.207. Per ottenere questo risultato utilizziamo ALL come funzione tabellare, che genera una tabella virtuale contenente tutte le righe della Fact Table Winesales, sulla quale la funzione COUNTROWS esegue il conteggio:

Grand Total No. of Sales =
    COUNTROWS(
        // generate a virtual table containing all the rows
        // of the Winesales fact table
        ALL(Winesales)
    )

A questo punto possiamo calcolare la percentuale di ciascun vino sul totale generale dividendo il numero di vendite nel contesto corrente per il totale globale:

No. of Sales as Percent of Grand Total =
    DIVIDE(
        [No. of Sales],             // nominator
        [Grand Total No. of Sales]  // denominator (use ALL)
    )
Uso della funzione ALL sulla Fact Table
Figura 1: Uso della funzione ALL sulla Fact Table

Vediamo ora cosa accade se applichiamo ulteriori filtri al report. Ad esempio, aggiungiamo uno slicer sulla Dimension Table SalesPeople. Come mostrato nel tab “ALL on Fact Tables”, la misura Grand Total No. of Sales, che utilizza la funzione ALL, continua a restituire sempre lo stesso valore, indipendentemente dal filtro selezionato nello slicer:

Grand Total No. of Sales =
    COUNTROWS(
        // generate a virtual table containing all the rows
        // of the Winesales fact table
        ALL(Winesales)
    )

Nel caso del vino “Bordeaux” (prima riga del visual), sono attivi contemporaneamente due filtri:

  1. un filtro sulla Dimension Table Wines, che seleziona il vino “Bordeaux”
  2. un filtro sulla Dimension Table SalesPeople, che seleziona il venditore “Abel”

Nonostante ciò, la funzione ALL ignora completamente i filtri propagati dalle Dimension Table, e conta sempre tutte le righe della tabella virtuale derivata da Winesales:

Rimozione dei filtri applicati alla Fact Table
Figura 2: Rimozione dei filtri applicati alla Fact Table

Consideriamo ora un secondo scenario, mostrato nel tab “ALL on Fact Tables (Calculate)”, in cui la funzione ALL viene utilizzata all’interno della funzione CALCULATE.

// Calculate the Grand Total Case (considering all the Winesales)
Total Cases All Winesales =
    CALCULATE(
        // expression to calculate
        [Total Cases],

        // FILTER MODIFIER that removes all the cross-filters
        // (do NOT generate a virtual table)
        ALL(Winesales)
    )

// Calculate the Average Total Case (considering all the Winesales)
Avg Cases All Winesales =
    CALCULATE(
        // expression to calculate
        AVERAGE(Winesales[CASES SOLD]),

        // FILTER MODIFIER that removes all the cross-filters
        // (do NOT generate a virtual table)
        ALL(Winesales)
   )

No. of Sales Where Cases is GT Avg All Wines =
    CALCULATE(
        // expression to calculate
        [No. of Sales],

        // table filter that materialize an intermediate table in memory,
        // but respects the current Filter Context
        FILTER (
            Winesales,
            Winesales[CASES SOLD] >= [Avg Cases All Winesales]
        )

In questo contesto, ALL(Winesales) non viene usata per restituire una tabella, ma agisce come Modificatore di Filtro di CALCULATE. Il suo effetto è quello di rimuovere tutti i filtri applicati alla Fact Table Winesales, inclusi quelli propagati dalle dimensioni, prima che venga valutata l’espressione della misura. Pertanto, ALL può quindi assumere due ruoli distinti, a seconda del contesto in cui viene utilizzata:

Contesto di UtilizzoDescrizione
Funzione TabellareRestituisce una tabella virtuale contenente tutte le righe della tabella o tutti i valori distinti delle colonne specificate.
Modificatore di FiltroAll’interno di CALCULATE, rimuove i filtri dalla tabella o dalle colonne indicate senza materializzare una tabella virtuale come risultato.

Nota: i Modificatori di Filtro di CALCULATE vengono valutati prima di qualsiasi altro argomento di filtro, rendendo ALL uno strumento fondamentale per controllare in modo esplicito il Filter Context.

Uso della funzione ALL come Modificatore di Filtro
Figura 3: Uso della funzione ALL come Modificatore di Filtro

ALL Sulle Dimension Table

Quando la funzione ALL viene applicata a una Dimension Table (ad esempio Wines), essa rimuove tutti i filtri attivi su quella dimensione, inclusi:

  • filtri provenienti da slicer,
  • filtri applicati da visual,
  • filtri introdotti implicitamente dal contesto di valutazione della misura.

Il risultato è il ripristino dell’insieme completo dei valori della Dimension Table. Poiché una Dimension Table è collegata a una Fact Table tramite una relazione, la rimozione dei filtri sulla tabella dimensionale ha un effetto indiretto anche sul Filter Context della Fact Table: la Fact Table non viene più filtrata da quella dimensione specifica. In altre parole, applicare ALL a una Dimension Table interrompe la propagazione dei filtri da quella dimensione verso la Fact Table. Riassumendo:

OperazioneDescrizione
ALL(DimensionTable)Rimuove i filtri dalla Dimension Table specificata; i filtri non vengono più propagati alla Fact Table tramite la relazione.
ALL(FactTable)Rimuove tutti i filtri dalla Fact Table, inclusi quelli propagati dalle Dimension Table collegate (ma i filtri attivi sulle Dimension Table non vengono cancellati).

Consideriamo il tab “ALL on Dimension Tables”, e le seguenti Misure:

// Measure: calculates the Number of Sales, considering the current Wines filter
No. Of Sales = COUNTROWS(Winesales)

// Measure: calculates the Grand Number of Sales, considering all the Wines
No. of Sales All Wines =
    CALCULATE(
        // expression to calculate
        [No. of Sales],
        // ALL removes all the filters on Wines Dimension Table
        ALL(Wines)
    )

// Measure: calculate the ratio
No. of Sales as Percent of Filtered Value =
    DIVIDE(
        [No. of Sales],           // nominator
        [No. of Sales All Wines]  // denominator (considers all the Wines)
    )

La misura No. Of Sales viene valutata nel Filter Context corrente e quindi risente di tutti i filtri applicati alle dimensioni, inclusi Wines e SalesPeople. Nella misura No. of Sales All Wines, invece, utilizziamo CALCULATE per modificare esplicitamente il Filter Context, rimuovendo solo i filtri dalla Dimension Table Wines tramite l’espressione ALL(Wines) usata come argomento di filtro:

Uso della funzione ALL sulle Dimension Table
Figura 4: Uso della funzione ALL sulle Dimension Table

Nel visual di tipo Table, inizialmente sono attivi due filtri principali:

  1. un filtro sulla Dimension Table Wines, introdotto implicitamente dal contesto di riga del visual (tramite Context Transition attivata da CALCULATE);
  2. un filtro sulla Dimension Table SalesPeople, introdotto dallo slicer.

Quando la misura No. of Sales All Wines viene valutata per ciascun vino (cioè per ciascuna riga del visual):

  • CALCULATE attiva la Context Transition;
  • ALL(Wines) rimuove tutti i filtri sulla Dimension Table Wines;
  • i filtri provenienti da altre dimensioni (come SalesPeople) rimangono attivi.

Di conseguenza, la Misura restituisce sempre lo stesso valore per tutti i vini, pari al numero di vendite complessive limitato solo dai filtri sulle altre dimensioni, ma indipendente dal vino selezionato nella riga:

Rimozione dei filtri sulla Dimension Table Wines
Figura 5: Rimozione dei filtri sulla Dimension Table Wines

È importante sottolineare che ALL(Wines) non rimuove direttamente i filtri dalla Fact Table Winesales; tuttavia, eliminando i filtri sulla dimensione Wines, viene meno anche il filtro propagato alla Fact Table tramite la relazione.

ALL Sulle Colonne

Quando ALL viene utilizzata specificando una o più colonne di una tabella, Power BI rimuove i filtri esclusivamente dalle colonne indicate, lasciando inalterati i filtri sulle altre colonne della stessa tabella. Questo comportamento è particolarmente utile quando si desidera controllare in modo selettivo il Filter Context, evitando di cancellare filtri che devono rimanere attivi (ad esempio filtri su attributi diversi della stessa Dimension Table). Consideriamo il tab “ALL on a Table Column” con le seguenti misure:

No. Of Sales = COUNTROWS(Winesales)

No. of Sales All Wines =
    CALCULATE(
        // expression to calculate
        [No. of Sales],

        // removes all the filters on Wines Dimension Table
        ALL(Wines)
    )

No. of Sales as Percent of Filtered Value =
    DIVIDE(
        [No. of Sales],           // nominator
        [No. of Sales All Wines]  // denominator
    )

Nel report sono attivi i seguenti filtri:

  1. un filtro sulla colonna Wines[WINE] (righe del visual),
  2. un filtro sul venditore “Abel” (slicer sulla dimensione SalesPeople),
  3. un filtro sul fornitore “Alliance” (slicer sulla colonna Wines[SUPPLIER]).

La misura No. of Sales All Wines utilizza ALL(Wines), che rimuove tutti i filtri dalla Dimension Table Wines, inclusi:

  • il filtro sul nome del vino (Wines[WINE]);
  • il filtro sul fornitore (Wines[SUPPLIER]).

Di conseguenza, la misura restituisce il totale delle vendite per il venditore “Abel”, considerando tutti i vini e tutti i fornitori, pari a 376, ignorando completamente la selezione del fornitore:

No. of Sales All Wines =
    CALCULATE(
        // expression to calculate
        [No. of Sales],

        // removes all the filters on Wines Dimension Table
        ALL(Wines)
    )

Questo risultato non è quello desiderato, perché il filtro sul fornitore dovrebbe rimanere attivo. Per risolvere il problema, è sufficiente rimuovere i filtri solo dalla colonna Wines[WINE], lasciando invariati quelli sulle altre colonne della dimensione, come Wines[SUPPLIER]. Creiamo quindi le seguenti Misure:

No. of Sales All Wines #2 =
    CALCULATE(
        // expression to calculate
        [No. of Sales],

        // removes filters only on Wines[WINE] column
        ALL(Wines[WINE])
    )

No. of Sales as Percent of Filtered Value #2 =
    DIVIDE(
        [No. of Sales],              // nominator
        [No. of Sales All Wines #2]  // denominator
    )
Uso della funzione ALL sulle colonne
Figura 6: Uso della funzione ALL sulle colonne

In questo caso, ALL(Wines[WINE]) rimuove solo il filtro sul nome del vino. Il filtro sul fornitore (Wines[SUPPLIER]) rimane attivo, e anche i filtri provenienti da altre dimensioni (ad esempio SalesPeople) continuano a influenzare il risultato. Il denominatore rappresenta quindi il totale delle vendite per il fornitore selezionato, limitato al venditore “Abel”, ma indipendente dal singolo vino visualizzato nella riga.

Questo esempio evidenzia perché, in molti casi, ALL applicata a una colonna è preferibile a ALL applicata all’intera tabella: consente di ottenere calcoli più precisi e controllati, evitando di rimuovere filtri che fanno parte della logica di business.

ALL Come Modificatore di Filtro, Reprise

Consideriamo il tab di esempio “ALL as a Modifier to CALCULATE #1”, con le seguenti Misure:

// Measure using ALL
No. of Wines #1 = COUNTROWS(
    // returns a table with all unique values of Wines[WINE],
    // ignoring any filters currently applied to that column
    // (from slicers, visuals, etc.)
    ALL(Wines[WINE])
)

// Measure using CALCULATE and a nested ALL
No. of Wines #2 = CALCULATE(
    // expression to calculate
    COUNTROWS(Wines),

    // filter modifier that removes filters only on Wines[WINE] column
    ALL(Wines[WINE])
)

La Misura No. of Wines #1 utilizza ALL come funzione tabellare. ALL(Wines[WINE]) genera una tabella virtuale a colonna singola che contiene tutti i valori distinti della colonna Wines[WINE], ignorando qualsiasi filtro proveniente da slicer o visual. La funzione COUNTROWS conta quindi il numero di righe di questa tabella virtuale, che è costante e pari a 14, indipendentemente dal Filter Context del report.

La misura No. of Wines #2, invece, utilizza ALL(Wines[WINE]) all’interno di CALCULATE. In questo caso, ALL non restituisce una tabella, ma agisce come Modificatore di Filtro, con il seguente comportamento:

  1. rimuove i filtri dalla colonna Wines[WINE];
  2. mantiene attivi tutti gli altri filtri, ad esempio quelli sulla colonna Wines[SUPPLIER] applicati tramite slicer.

Di conseguenza, la Misura conta il numero di righe della Dimension Table Wines, ma il risultato varia in base ai filtri ancora attivi (come SUPPLIER):

// Measure using CALCULATE and a nested ALL
No. of Wines #2 = CALCULATE(
    // expression to calculate
    COUNTROWS(Wines),

    // FILTER MODIFIER that removes filters only on Wines[WINE] column,
    // and keeps other filters active
    ALL(Wines[WINE])
)
Uso della funzione ALL come modificatore di filtro (2)
Figura 7: Uso della funzione ALL come modificatore di filtro (2)

Il comportamento di ALL come Modificatore di Filtro può risultare meno intuitivo in scenari più complessi. Consideriamo ora il tab “ALL as a Modifier to CALCULATE #2”, con le seguenti Misure:

No. of Sales Where Cases GT 300 #1 =
    CALCULATE(
        // expression to calculate
        [No. of Sales],
        // filter modifier that removes all the filters on Winesales
        ALL(Winesales),
        // column filter
        Winesales[CASES SOLD] > 300
    )

No. of Sales Where Cases GT 300 #2 =
    CALCULATE(
        // expression to calculate
        [No. of Sales],
        // filter that materializes an intermediate table in memory
        FILTER(
            // removes all the filters on Winesales
            ALL(Winesales),

            // column filter on CASES SOLD
            Winesales[CASES SOLD] > 300
        )
    )

No. of Sales Where Cases GT 300 #3 =
    CALCULATE(
        // expression to calculate
        [No. of Sales],
        // filter modifier that removes filters on Winesales
        ALL(Winesales),
        // filter that materializes an intermediate table in memory
        FILTER(
            // filter table (consider the current filter on Winesales)
            Winesales,
            // column filter
            Winesales[CASES SOLD] > 300
        )
    )

In questo esempio, le Misure #1 e #2 restituiscono lo stesso valore, mentre la Misura #3 restituisce un valore diverso. Tutte e tre utilizzano ALL(Winesales), quindi ci si aspetterebbe che ignorino qualsiasi filtro sulla Fact Table Winesales. Questo avviene correttamente solo nelle Misure #1 e #2. Perché la Misura #3 è diversa?

Nella Misura #3, ALL(Winesales) rimuove inizialmente i filtri sulla Fact Table, ma il filtro tabellare successivo:

FILTER(
    // filter table (consider the current filter on Winesales)
    Winesales,
    // column filter
    Winesales[CASES SOLD] > 300
)

viene valutato nel Filter Context corrente.

È fondamentale ricordare che: FILTER rispetta sempre il Filter Context attivo al momento della sua valutazione.

In questo caso:

  • tramite la colonna WINE, il visual applica un filtro sulla Dimension Table Wines (ad esempio: Wines[WINE] = "Bordeaux"). Tale filtro viene propagato a Winesales tramite la relazione tra le due tabelle;
  • ALL(Winesales) rimuove i filtri diretti sulla Fact Table, ma il filtro su Wines[WINE] rimane attivo;
  • FILTER(Winesales, …), rispettando il Filter Context, materializza una tabella intermedia sensibile al filtro Wines[WINE], ancora attivo. Tale tabella conterrà solo le righe del vino corrente. Su questo sottoinsieme viene poi applicata la condizione CASES SOLD > 300.

Di conseguenza, la misura #3 restituisce il numero di vendite per ciascun vino, invece del totale globale:

Uso della funzione ALL (6)
Figura 8: Uso della funzione ALL (6)

Riassumendo

  • ALL come funzione tabellare:
    genera una tabella virtuale contenente tutte le righe di una tabella, o tutte le righe distinte di una o più colonne.

  • ALL come modificatore di filtro:
    viene valutata prima di qualsiasi argomento di filtro all’interno di CALCULATE. In questo caso, ALL rimuove tutti i filtri da una tabella o da una colonna, e genera un filtro vuoto.

Poiché ALL ha un comportamento diverso quando viene utilizzato come come modificatore di filtro internamente a CALCULATE, nel 2019, la libreria DAX ha introdotto la funzione REMOVEFILTERS, sinonimo di ALL, che può essere utilizzata solo come modificatore di filtro CALCULATE, e non come espressione tabellare.