Salta al contenuto

Calcoli progressivi dinamici in presenza di elementi di pari valore

Nel precedente articolo sull’argomento, disponibile qui, è stato mostrato come creare calcoli progressivi statici in presenza di elementi di pari valore, scegliendo l’ordinamento alfabetico come criterio di scelta di priorità . Il calcolo è stato definito statico in quanto effettuato in una colonna calcolata e, dunque, calcolato una volta per tutte in fase di creazione della colonna calcolata stessa e, successivamente, in fase di refresh.

In questo articolo verrà illustrata la versione dinamica dello stesso calcolo, attraverso la sintesi di una misura che si adatterà al contesto di un report.

La parte sfindante del passaggio da una colonna calcolata ad una misura (e viceversa) risiede sempre nel filter context che è – a meno di filtri introdotti con CALCULATE – vuoto nel caso di una colonna calcolata e – nella maggior parte dei casi – non vuoto in un report.

L’impanto base presente nella colonna del precedente articolo, tra cui l’uso di RANKX e il criterio alfabetico di scelta in presenza di elementi di pari valore, resterà valido; tuttavia andranno fatte delle modifiche di codice nel passare da una colonna calcolata ad una misura, in particolare sarà necessario usare la funzione ALLSELECTED come modificatore di CALCULATE.

Il modello dati è lo stesso del precedente articolo.

Sviluppo

La prima idea che potrebbe venire in mente, nel volere rappresentare in un report – dunque usando una misura – i calcoli svolti nella colonna calcolata Clienti[Progressivo Vendite Evoluto] oggetto del precedente articolo, è di aggregare la colonna stessa, usando il seguente codice:

Vendite progressive evolute statiche =
SUM ( Clienti[Progressivo Vendite Evoluto] )

Tuttavia, con tale codice si ottiene un totale errato al totale, come è visibile in figura 1.

Il totale progressivo dovrebbe, infatti, essere pari a 1.200. Il problema è che la colonna che stiamo aggregando è già una colonna già di valori progressivi. Il problema può essere “risolto”, in modo tuttavia poco elegante e poco efficace, nascondendo il totale con il codice a seguire, il cui risultato è visibile in figura 2. Ciò crea, tuttavia, un report che non mostra alcun valore al totale e, peggio ancora, nessun valore in assoluto se il cliente non è presente in riga o colonna nella matrice, come si può evincere dalla figura 3.

Vendite progressive evolute statiche =
IF (
    ISINSCOPE ( Clienti[Clienti] ),
    SUM ( Clienti[Progressivo Vendite Evoluto] )
)
Figura 2
Figura 3

Inoltre, che succede se, attraverso lo slicer visibile nella figure sopra riportate, si selezionano soltanto alcuni clienti? La figura 4 mostra l’effetto della selezione sulla misura.

Figura 4

Come si vede, la misura restituisce un valore errato (1.200 invece di 1.100) in corrispondenza del cliente D, l’ultimo dell’elenco. Il problema è che si sta aggregando un calcolo, ancora una volta, statico in quanto scritto in una colonna calcolata. Tale colonna, per il cliente D, prevede un progressivo di 1.200. La selezione fatta sullo slicer, che esclude il cliente E, modifica il filter context del report ma non il valore progressivo della colonna Clienti[Progressivo Vendite Evoluto] che riporta ancora gli stessi valori di prima, a parte la mancanza del cliente E tra i clienti listati. Si nota, anche, che il valore progressivo per il cliente G è ancora 1.100 mentre dovrebbe essere 1.000. il tutto per la stesse ragioni appena enunciate per il cliente D.

Come risolvere, dunque? A seguire il risultato desiderato, in figura 5.

Figura 5

Come si vede, il calcolo nel riquadro rosso in figura 5 mostra i valori corretti, anche in presenza di una selezione sui clienti.

La misura Vendite Progressive evolute dinamiche ha il seguente codice, commentato a seguire per i meno esperti.

Vendite Progressive evolute dinamiche =
VAR Margine = [Margine medio]
VAR ClientiEMargini =
    ADDCOLUMNS (
        CALCULATETABLE ( VALUES ( Clienti[Clienti] )ALLSELECTED () ),
        “@Margine Medio”, [Margine medio]
    )
VAR RankingClienteMargine =
    RANKX (
        FILTER ( ClientiEMargini, [@Margine Medio] = Margine ),
        CALCULATE ( SELECTEDVALUE ( Clienti[Clienti] ) )
    )
RETURN
    IF (
        ISINSCOPE ( Clienti[Clienti] ),
        SUMX (
            FILTER ( ClientiEMargini, [@Margine Medio] >= Margine ),
            IF (
                [@Margine Medio] > Margine,
                CALCULATE ( SUM ( Vendite[Ricavi] ) ),
                VAR RankingClienteMargineIterazione =
                    RANKX (
                        FILTER ( ClientiEMargini, [@Margine Medio] = Margine ),
                        CALCULATE ( SELECTEDVALUE ( Clienti[Clienti] ) )
                    )
                RETURN
                    IF (
                        RankingClienteMargineIterazione >= RankingClienteMargine,
                        CALCULATE ( SUM ( Vendite[Ricavi] ) )
                    )
            )
        ),
        CALCULATE ( SUM ( Vendite[Ricavi] )ALLSELECTED () )
    )

Ecco la versione commentata:

Vendite Progressive evolute dinamiche =
// Nella variabile Margine conservo il margine medio percentuale
// del cliente correntemente nel filter context 
VAR Margine = [Margine medio] 
// Nella variabile ClientiEMargini creo l’elenco di tutti 

// i clienti selezionati all’esterno della visual e aggiungo il 
// calcolo del margine medio percentuale per ognuno tramite una
// colonna calcolata
VAR ClientiEMargini =
    ADDCOLUMNS (
        CALCULATETABLE ( VALUES ( Clienti[Clienti] )ALLSELECTED () ),
        “@Margine Medio”, [Margine medio]
    ) 
// Nella variabile RankingClienteMargine conservo la posizione 

// alfabetica del nome del cliente correntemente nel filter context 
// rispetto a quello di tutti i clienti con lo stesso margine medio 
// percentuale
VAR RankingClienteMargine =
    RANKX (
        FILTER ( ClientiEMargini, [@Margine Medio] = Margine ),
        CALCULATE ( SELECTEDVALUE ( Clienti[Clienti] ) )
    )
RETURN
    //se un cliente è in vista…
    IF (
        ISINSCOPE ( Clienti[Clienti] ),
        // Itero la tabella Clienti, limitata ai clienti che hanno margine medio 
        // percentuale maggiore o uguale a quello del cliente correntemente nel filter 
        // context. Lo faccio tramite SUMX per sommare tutti gli importi di 
        // vendita dei clienti con margine maggiore di quello del cliente correntemente 
        // nel filter context, e di quelli con margine uguale ma ordine 
        // alfabetico del nome prioritario
        SUMX (
            FILTER ( ClientiEMargini, [@Margine Medio] >= Margine ),
            IF (
                [@Margine Medio] > Margine,
                // se il margine medio percentuale del
                // cliente correntemente iterato è maggiore di quello del cliente 
                // correntemente nel filter context, sommo le vendite relative senza 
                // curarmi di altro (eventuali altri clienti con lo stesso margine 
                // possono essere sommati, essendo il margine strettamente
                // superiore a quello che cliente correntemente nel filter context)
                CALCULATE (
                    SUM ( Vendite[Ricavi] )
                ),
                // se, invece, il margine medio percentuale del cliente correntemente iterato è 
                // uguale a quello del cliente correntemente nel filter context, stabilisco la 
                // posizione, in termini di ordine alfabetico, del nome del cliente correntemente 
                // iterato rispetto a quello di tutti gli altri clienti con lo stesso margine, nella 
                // variabile RankingCLienteMargineIterazione
                VAR RankingClienteMargineIterazione =
                    RANKX (
                        FILTER ( ClientiEMargini, [@Margine Medio] = Margine ),
                        CALCULATE ( SELECTEDVALUE ( Clienti[Clienti] ) )
                    )
                RETURN
                    // Sommo, infine, solo le vendite dei clienti iterati con lo stesso
                    // margine di quello correntemente nel filter context ma con ordine 
                    // alfabetico del nome prioritario
                    IF (
                        RankingClienteMargineIterazione >= RankingClienteMargine,
                        CALCULATE ( SUM ( Vendite[Ricavi] ) )
                    )
            )
        ),
        //…altrimenti calcolo il totale su tutti i clienti selezionati al di fuori della visual
        CALCULATE (
            SUM ( Vendite[Ricavi] ),
            ALLSELECTED ()
        )
    )

Conclusioni

Nel passare da una colonna calcolata ad una misura, cioè da un calcolo statico ad uno dinamico, va posta attenzione alla presenza del filter context ed è dunque necessario spesso usare la funzione ALLSELECTED per recuperare una lista di valori esterna rispetto alla visualizzazione che mostra i valori della misura stessa. Non è suggerito usare ALLSELECTED come funzione tabellare, mentre è opportuno usarla come modificatore di CALCULATE. Si ricorda, infatti, che la reale funzione di ALLSELECTED non ha nulla a che vedere con le visualizzazioni. Usando, tuttavia, ALLSELECTED come modificatore di CALCULATE, con l’accortezza di non annidarla all’interno di iterazioni profonde, evitando così context transition poco facilmente rintracciabili, si ottiene il risultato voluto in modo relativamente semplice.

Autore del Post

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *