Del via


Forstå ORDERBY, PARTITIONBY, andMATCHBY funksjoner

Funksjonene ORDERBY, PARTITIONBY, andMATCHBY i DAX er spesielle funksjoner som bare kan brukes sammen med DAXWindow funksjoner: INDEX, OFFSET, WINDOW, RANK, ROWNUMBER.

Å forstå ORDERBY, PARTITIONBY, andMATCHBY er avgjørende for å kunne bruke Window-funksjonene. Eksemplene som er angitt her, bruker OFFSET, men gjelder på samme måte som de andre Window funksjonene.

Scenario

La oss starte med et eksempel som ikke bruker Window funksjoner på all. Vist nedenfor er en tabell som returnerer totalt salg, per farge, per calendaryear. Det finnes flere måter å define denne tabellen på, men siden vi er interessert i å forstå hva som skjer i DAX, bruker vi en beregnet tabell. Her er tabelluttrykket:

BasicTable = 
    SUMMARIZECOLUMNS ( 
        DimProduct[Color], 
        DimDate[CalendarYear], 
        "CurrentYearSales", ROUND ( SUM ( FactInternetSales[SalesAmount] ), 0 )
    )

Du ser at dette beregnede tabelluttrykket bruker SUMMARIZECOLUMNS til å calculateSUM i SalesAmount-kolonnen i FactInternetSales-tabellen, etter Farge-kolonnen fra DimProduct-tabellen, and CalendarYear-kolonnen fra DimDate-tabellen. Her er resultatet:

Farge CalendarYear CurrentYearSales
"Svart" 2017 393885
"Svart" 2018 1818835
"Svart" 2019 3981638
"Svart" 2020 2644054
"Blå" 2019 994448
"Blå" 2020 1284648
"Multi" 2019 48622
"Multi" 2020 57849
"NA" 2019 207822
"NA" 2020 227295
"Rød" 2017 2961198
"Rød" 2018 3686935
"Rød" 2019 900175
"Rød" 2020 176022
"Sølv" 2017 326399
"Sølv" 2018 750026
"Sølv" 2019 2165176
"Sølv" 2020 1871788
"Hvit" 2019 2517
"Hvit" 2020 2589
"Gul" 2018 163071
"Gul" 2019 2072083
"Gul" 2020 2621602

Now, la oss forestille oss at vi prøver å løse forretningsspørsmålet om å beregne forskjellen i salg, year-over-year for hver farge. Effektivt trenger vi en måte å find salg for samme farge i previousyearand trekke det fra salget i gjeldende year, i kontekst. For kombinasjonen [Rød, 2019] ser vi for eksempel etter salg for [Rød, 2018]. Når vi har det, kan vi deretter trekke det fra gjeldende salg and returnere den nødvendige value.

Bruke OFFSET

OFFSET er perfekt for den typiske sammenligne med previous typer beregninger som kreves for å svare på forretningsspørsmålet beskrevet ovenfor, da det tillater oss å gjøre en relativ bevegelse. Vårt first forsøk kan være:

1stAttempt = 
    VAR vRelation = SUMMARIZECOLUMNS ( 
        DimProduct[Color], 
        DimDate[CalendarYear], 
        "CurrentYearSales", ROUND ( SUM ( FactInternetSales[SalesAmount] ), 0 )
        )
    RETURN
    ADDCOLUMNS (
        vRelation,
        "PreviousColorSales",
        SELECTCOLUMNS (
            OFFSET (
                -1,
                vRelation
            ),
            [CurrentYearSales]
        )
    )

Mye skjer med dette uttrykket. Vi brukte ADDCOLUMNS til å expand tabellen fra før med en kolonne kalt PreviousColorSales. Innholdet i denne kolonnen er satt til CurrentYearSales, som er SUM(FactInternetSales[SalesAmount]), for previous Farge (hentet ved hjelp av OFFSET).

Resultatet er:

Farge CalendarYear CurrentYearSales PreviousColorSales
"Svart" 2017 393885
"Svart" 2018 1818835 393885
"Svart" 2019 3981638 1818835
"Svart" 2020 2644054 3981638
"Blå" 2019 994448 2644054
"Blå" 2020 1284648 994448
"Multi" 2019 48622 1284648
"Multi" 2020 57849 48622
"NA" 2019 207822 57849
"NA" 2020 227295 207822
"Rød" 2017 2961198 227295
"Rød" 2018 3686935 2961198
"Rød" 2019 900175 3686935
"Rød" 2020 176022 900175
"Sølv" 2017 326399 176022
"Sølv" 2018 750026 326399
"Sølv" 2019 2165176 750026
"Sølv" 2020 1871788 2165176
"Hvit" 2019 2517 1871788
"Hvit" 2020 2589 2517
"Gul" 2018 163071 2589
"Gul" 2019 2072083 163071
"Gul" 2020 2621602 2072083

Dette er ett skritt nærmere målet vårt, men if vi ser nøye på, samsvarer det ikke nøyaktig med det vi er ute etter. For [Silver, 2017] er for eksempel PreviousColorSales satt til [Rød, 2020].

Legge til ORDERBY

Denne definisjonen ovenfor tilsvarer:

1stAttemptWithORDERBY = 
    VAR vRelation = SUMMARIZECOLUMNS ( 
        DimProduct[Color], 
        DimDate[CalendarYear], 
        "CurrentYearSales", ROUND ( SUM ( FactInternetSales[SalesAmount] ), 0 )
        )
    RETURN
    ADDCOLUMNS (
        vRelation,
        "PreviousColorSales",
        SELECTCOLUMNS (
            OFFSET (
                -1,
                vRelation,
                ORDERBY ([Color], ASC, [CalendarYear], ASC, [CurrentYearSales], ASC)
            ),
            [CurrentYearSales]
        )
    )

I dette tilfellet bruker kallet til OFFSETORDERBY til å bestille tabellen etter Color and CalendarYear i stigende rekkefølge, som bestemmer hva som regnes som den previous raden som returneres.

Årsaken til at disse to resultatene tilsvarer, skyldes at ORDERBY automatisk containsall kolonner fra relasjonen som ikke er i PARTITIONBY. Siden PARTITIONBY ikke ble angitt, er ORDERBY satt til Color, CalendarYear, and CurrentYearSales. Men siden Color and CalendarYear-parene i relasjonen er unike, endrer ikke det å legge til CurrentYearSales resultatet. I factevenif vi bare skulle angi Farge i ORDERBY, er resultatene de samme siden CalendarYear legges til automatisk. Dette er fordi funksjonen vil legge til så mange kolonner som nødvendig for å ORDERBY for å sikre at hver rad kan identifiseres unikt av de ORDERBYandPARTITIONBY kolonnene:

1stAttemptWithORDERBY = 
    VAR vRelation = SUMMARIZECOLUMNS ( 
        DimProduct[Color], 
        DimDate[CalendarYear], 
        "CurrentYearSales", ROUND ( SUM ( FactInternetSales[SalesAmount] ), 0 )
        )
    RETURN
    ADDCOLUMNS(
        vRelation,
        "PreviousColorSales",
        SELECTCOLUMNS (
            OFFSET (
                -1,
                vRelation,
                ORDERBY ([Color])
            ),
            [CurrentYearSales]
        )
    )

Legge til PARTITIONBY

Now, for å nesten få resultatet vi er ute etter, kan vi bruke PARTITIONBY, som vist i følgende beregnede tabelluttrykk:

UsingPARTITIONBY = 
    VAR vRelation = SUMMARIZECOLUMNS ( 
        DimProduct[Color], 
        DimDate[CalendarYear], 
        "CurrentYearSales", ROUND ( SUM ( FactInternetSales[SalesAmount] ), 0 )
        )
    RETURN
    ADDCOLUMNS (
        vRelation,
        "PreviousColorSales",
        SELECTCOLUMNS (
            OFFSET (
                -1,
                vRelation,
                ORDERBY ([CalendarYear]), 
                PARTITIONBY ([Color])
            ),
            [CurrentYearSales]
        )
    )

Legg merke til at det er valgfritt å angi ORDERBY her fordi ORDERBY automatisk containsall kolonnene fra relasjonen som ikke er angitt i PARTITIONBY. Så følgende uttrykk returnerer de samme resultatene fordi ORDERBY er satt til CalendarYear and CurrentYearSales automatisk:

UsingPARTITIONBYWithoutORDERBY = 
    VAR vRelation = SUMMARIZECOLUMNS ( 
        DimProduct[Color], 
        DimDate[CalendarYear], 
        "CurrentYearSales", ROUND ( SUM ( FactInternetSales[SalesAmount] ), 0 )
        )
    RETURN
    ADDCOLUMNS (
        vRelation,
        "PreviousColorSales",
        SELECTCOLUMNS (
            OFFSET (
                -1,
                vRelation,
                PARTITIONBY ([Color])
            ),
            [CurrentYearSales]
        )
    )

Notat

Selv om ORDERBY er satt til CalendarYear and CurrentYearSales automatisk, gis det ingen garanti for hvilken rekkefølge de skal legges til. If CurrentYearSales legges til før CalendarYear, er ikke den resulterende rekkefølgen linjebundet med det som forventes. Vær eksplisitt når du angir ORDERBYandPARTITIONBY for å unngå forvirring and uventede resultater.

Begge uttrykkene returnerer resultatet vi er ute etter:

Farge CalendarYear CurrentYearSales PreviousYearSalesForSameColor
"Svart" 2017 393885
"Svart" 2018 1818835 393885
"Svart" 2019 3981638 1818835
"Svart" 2020 2644054 3981638
"Blå" 2019 994448
"Blå" 2020 1284648 994448
"Multi" 2019 48622
"Multi" 2020 57849 48622
"NA" 2019 207822
"NA" 2020 227295 207822
"Rød" 2017 2961198
"Rød" 2018 3686935 2961198
"Rød" 2019 900175 3686935
"Rød" 2020 176022 900175
"Sølv" 2017 326399
"Sølv" 2018 750026 326399
"Sølv" 2019 2165176 750026
"Sølv" 2020 1871788 2165176
"Hvit" 2019 2517
"Hvit" 2020 2589 2517
"Gul" 2018 163071
"Gul" 2019 2072083 163071
"Gul" 2020 2621602 2072083

Som du ser i denne tabellen, viser Kolonnen PreviousYearSalesForSameColor salg for previousyear for samme farge. For [Rød, 2020], returnerer den salget for [Rød, 2019], and så videre. If det ikke finnes noen previousyear, for eksempel når det gjelder [Rød, 2017], returneres ingen value.

Du kan tenke på PARTITIONBY som en måte å divide tabellen i deler der du kan utføre OFFSET beregningen. I eksemplet ovenfor er tabellen delt inn i så mange deler som det finnes farger, én for hver farge. Deretter beregnes OFFSET i hver del, sortert etter CalendarYear.

Visuelt er det som skjer dette:

tabell som viser OFFSET av CalendarYear

Firstfører kallet til PARTITIONBY til at tabellen deles inn i deler, én for hver farge. Dette representeres av de lyseblå boksene i tabellbildet. Nextsørger ORDERBY for at hver del er sortert etter CalendarYear (representert av de oransje pilene). Til slutt finner OFFSET raden over hver sortert del, and returnerer den value i Kolonnen PreviousYearSalesForSameColor. Siden for hver first rad i hver del er det ingen previous rad i den samme delen, er resultatet i raden for PreviousYearSalesForSameColor-kolonnen tom.

For å oppnå det endelige resultatet må vi ganske enkelt trekke fra CurrentYearSales fra previousyear salg for samme farge som ble returnert av kallet til OFFSET. Siden vi er not interessert i å vise previousyear salg for samme farge, men bare i gjeldende year salg andyear over year forskjell. Her er det endelige beregnede tabelluttrykket:

FinalResult = 
    VAR vRelation = SUMMARIZECOLUMNS ( 
        DimProduct[Color], 
        DimDate[CalendarYear], 
        "CurrentYearSales", ROUND ( SUM ( FactInternetSales[SalesAmount] ), 0 )
        )
    RETURN
    ADDCOLUMNS (
        vRelation,
        "YoYSalesForSameColor",
        [CurrentYearSales] -
        SELECTCOLUMNS (
            OFFSET (
                -1,
                vRelation,
                ORDERBY ([CalendarYear]),
                PARTITIONBY ([Color])
            ),
            [CurrentYearSales]
        )
    )

And her er resultatet av uttrykket:

Farge CalendarYear CurrentYearSales YoYSalesForSameColor
"Svart" 2017 393885 393885
"Svart" 2018 1818835 1424950
"Svart" 2019 3981638 2162803
"Svart" 2020 2644054 -1337584
"Blå" 2019 994448 994448
"Blå" 2020 1284648 290200
"Multi" 2019 48622 48622
"Multi" 2020 57849 9227
"NA" 2019 207822 207822
"NA" 2020 227295 19473
"Rød" 2017 2961198 2961198
"Rød" 2018 3686935 725737
"Rød" 2019 900175 -2786760
"Rød" 2020 176022 -724153
"Sølv" 2017 326399 326399
"Sølv" 2018 750026 423627
"Sølv" 2019 2165176 1415150
"Sølv" 2020 1871788 -293388
"Hvit" 2019 2517 2517
"Hvit" 2020 2589 72
"Gul" 2018 163071 163071
"Gul" 2019 2072083 1909012
"Gul" 2020 2621602 549519

Bruke MATCHBY

Du har kanskje lagt merke til at vi ikke spesifiserte MATCHBY på all. I dette tilfellet er det ikke nødvendig. Kolonnene i ORDERBYandPARTITIONBY (så langt de ble angitt i eksemplene ovenfor) er tilstrekkelige til å identifisere hver rad unikt. Siden vi ikke angir MATCHBY, brukes kolonnene som er angitt i ORDERBYandPARTITIONBY til å identifisere hver rad unikt, slik at de kan sammenlignes for å aktivere OFFSET for å gi et meningsfullt resultat. If kolonnene i ORDERBYandPARTITIONBY ikke unikt kan identifisere hver rad, kan du legge til flere kolonner i ORDERBY setningsdelen if disse ekstra kolonnene tillater at hver rad identifiseres unikt. If det er not mulig, returneres en error. I dette last tilfellet kan det å angi MATCHBY bidra til å løse error.

If MATCHBY er angitt, brukes kolonnene i MATCHBYandPARTITIONBY til å identifisere hver rad unikt. If det er not mulig, returneres en error. Even if MATCHBY ikke er nødvendig, bør du vurdere å eksplisitt angi MATCHBY for å unngå forvirring.

Hvis du fortsetter fra eksemplene ovenfor, kan du se uttrykket last:

FinalResult = 
    VAR vRelation = SUMMARIZECOLUMNS ( 
        DimProduct[Color], 
        DimDate[CalendarYear], 
        "CurrentYearSales", ROUND ( SUM ( FactInternetSales[SalesAmount] ), 0 )
        )
    RETURN
    ADDCOLUMNS (
        vRelation,
        "YoYSalesForSameColor",
        [CurrentYearSales] -
        SELECTCOLUMNS (
            OFFSET (
                -1,
                vRelation,
                ORDERBY ([CalendarYear]),
                PARTITIONBY ([Color])
            ),
            [CurrentYearSales]
        )
    )

If vi ønsker å være eksplisitte om hvordan rader skal identifiseres unikt, kan vi angi MATCHBY som vist i følgende tilsvarende uttrykk:

FinalResultWithExplicitMATCHBYOnColorAndCalendarYear = 
    VAR vRelation = SUMMARIZECOLUMNS ( 
        DimProduct[Color], 
        DimDate[CalendarYear], 
        "CurrentYearSales", ROUND ( SUM ( FactInternetSales[SalesAmount] ), 0 )
        )
    RETURN
    ADDCOLUMNS (
        vRelation,
        "YoYSalesForSameColor",
        [CurrentYearSales] -
        SELECTCOLUMNS (
            OFFSET (
                -1,
                vRelation,
                ORDERBY ([CalendarYear]),
                PARTITIONBY ([Color]),
                MATCHBY ([Color], [CalendarYear])
            ),
            [CurrentYearSales]
        )
    )

Siden MATCHBY er angitt, brukes både kolonnene som er angitt i MATCHBY og i PARTITIONBY til å identifisere rader unikt. Siden farge er angitt i begge MATCHBYandPARTITIONBY, tilsvarer følgende uttrykk previous-uttrykket:

FinalResultWithExplicitMATCHBYOnCalendarYear = 
    VAR vRelation = SUMMARIZECOLUMNS ( 
        DimProduct[Color], 
        DimDate[CalendarYear], 
        "CurrentYearSales", ROUND ( SUM ( FactInternetSales[SalesAmount] ), 0 )
        )
    RETURN
    ADDCOLUMNS (
        vRelation,
        "YoYSalesForSameColor",
        [CurrentYearSales] -
        SELECTCOLUMNS (
            OFFSET (
                -1,
                vRelation,
                ORDERBY ([CalendarYear]),
                PARTITIONBY ([Color]),
                MATCHBY ([CalendarYear])
            ),
            [CurrentYearSales]
        )
    )

Siden det ikke er nødvendig å angi MATCHBY i eksemplene vi har sett på så langt, kan vi se på et litt annet eksempel som krever MATCHBY. I dette tilfellet har vi en liste over ordrelinjer. Hver rad representerer en ordrelinje for en ordre. En ordre kan ha flere ordrelinjer and ordrelinje 1 vises på mange ordrer. For hver ordrelinje har vi i tillegg en ProductKey-and en SalesAmount. En sample av de relevante kolonnene i tabellen ser slik ut:

SalesOrderNumber SalesOrderLineNumber ProductKey SalesAmount
SO51900 1 528 4.99
SO51948 1 528 5.99
SO52043 1 528 4.99
SO52045 1 528 4.99
SO52094 1 528 4.99
SO52175 1 528 4.99
SO52190 1 528 4.99
SO52232 1 528 4.99
SO52234 1 528 4.99
SO52234 2 529 3.99

Legg merke til SalesOrderNumber and SalesOrderLineNumber kreves begge for å identifisere rader unikt.

For hver ordre ønsker vi å returnere det previous salgsbeløpet på samme product (representert av ProductKey) bestilt av SalesAmount i synkende rekkefølge. Følgende uttrykk fungerer ikke fordi det er potensielt flere rader i vRelation når det sendes inn i OFFSET:

ThisExpressionFailsBecauseMATCHBYIsMissing = 
    ADDCOLUMNS (
        FactInternetSales,
        "Previous Sales Amount",
            SELECTCOLUMNS (
                OFFSET (
                    -1,
                    FactInternetSales,
                    ORDERBY ( FactInternetSales[SalesAmount], DESC ),
                    PARTITIONBY ( FactInternetSales[ProductKey] )
                ),
                FactInternetSales[SalesAmount]
            )
    )

Dette uttrykket returnerer en error: "OFFSETrelasjonsparameteren kan ha dupliserte rader, som ikke er tillatt."

Hvis du vil at dette uttrykket skal fungere, må MATCHBY angis and må inneholde all kolonner som unikt define en rad. MATCHBY kreves her fordi relasjonen FactInternetSales ikke inneholder noen eksplisitte nøkler or unike kolonner. Kolonnene SalesOrderNumber and SalesOrderLineNumber utgjør imidlertid en sammensatt nøkkel, der deres eksistens sammen er unik i relasjonen and kan derfor unikt identifisere hver rad. Bare angi SalesOrderNumber or SalesOrderLineNumber er ikke nok, da begge kolonnene inneholder gjentatte values. Følgende uttrykk løser problemet:

ThisExpressionWorksBecauseOfMATCHBY = 
    ADDCOLUMNS (
        FactInternetSales,
        "Previous Sales Amount",
            SELECTCOLUMNS (
                OFFSET (
                    -1,
                    FactInternetSales,
                    ORDERBY ( FactInternetSales[SalesAmount], DESC ),
                    PARTITIONBY ( FactInternetSales[ProductKey] ),
                    MATCHBY ( FactInternetSales[SalesOrderNumber], 
                                FactInternetSales[SalesOrderLineNumber] )
                ),
                FactInternetSales[SalesAmount]
            )
    )

And dette uttrykket returnerer faktisk resultatene vi er ute etter:

SalesOrderNumber SalesOrderLineNumber ProductKey SalesAmount Previous salgsbeløp
SO51900 1 528 5.99
SO51948 1 528 4.99 5.99
SO52043 1 528 4.99 4.99
SO52045 1 528 4.99 4.99
SO52094 1 528 4.99 4.99
SO52175 1 528 4.99 4.99
SO52190 1 528 4.99 4.99
SO52232 1 528 4.99 4.99
SO52234 1 528 4.99 4.99
SO52234 2 529 3.99

ORDERBY PARTITIONBY MATCHBY INDEX OFFSET WINDOW RANK ROWNUMBER