Zdieľať cez


Základné informácie o funkciách ORDERBY, PARTITIONBYa MATCHBY

Funkcie ORDERBY, PARTITIONBYa MATCHBY v DAX sú špeciálne funkcie, ktoré možno použiť len spolu s funkciami DAX Window: INDEX, OFFSET, WINDOW, RANK, ROWNUMBER.

Pre úspešné používanie funkcií okna je nevyhnutné porozumieť ORDERBY, PARTITIONBYa MATCHBY. Príklady uvedené v tomto článku používajú OFFSET, ale sú podobné ako v prípade ostatných funkcií okna.

Scenár

Začnime s príkladom, ktorý vôbec nepoužíva funkcie okna. Zobrazená nižšie je tabuľka, ktorá vráti celkový predaj na farbu pre kalendárny rok. Tabuľku je možné definovať viacerými spôsobmi, ale keďže máme záujem pochopiť, čo sa stane v DAX, použijeme vypočítavanú tabuľku. Tu je výraz tabuľky:

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

Výraz vypočítanej tabuľky používa SUMMARIZECOLUMNS na výpočet SUM stĺpca ObjemPredaja v tabuľke FactInternetSales podľa stĺpca Color z tabuľky DimProduct a stĺpca CalendarYear z tabuľky DimDate. Tu je výsledok:

Farba KalendárnyRok CurrentYearSales (AktuálnyPredajRoku)
"Black" (Čierna) 2017 393885
"Black" (Čierna) 2018 1818835
"Black" (Čierna) 2019 3981638
"Black" (Čierna) 2020 2644054
"Modrá" 2019 994448
"Modrá" 2020 1284648
"Multi" 2019 48622
"Multi" 2020 57849
"NA" 2019 207822
"NA" 2020 227295
"Red" (červená) 2017 2961198
"Red" (červená) 2018 3686935
"Red" (červená) 2019 900175
"Red" (červená) 2020 176022
"Strieborné" 2017 326399
"Strieborné" 2018 750026
"Strieborné" 2019 2165176
"Strieborné" 2020 1871788
"Biela" 2019 2517
"Biela" 2020 2589
"Žltá" 2018 163071
"Žltá" 2019 2072083
"Žltá" 2020 2621602

Teraz si predstavme, že sa snažíme vyriešiť obchodnú otázku výpočtu rozdielu predaja pre každú farbu medziročne. Potrebujeme teda nájsť spôsob, ako vyhľadať predaj pre rovnakú farbu v predchádzajúcom roku a odpočítať ho od predaja v aktuálnom roku v kontexte. Napríklad pre kombináciu [Červená, 2019] hľadáme predaj pre [Červená, 2018]. Keď to bude mať, môžeme ju odčítať od aktuálneho predaja a vrátiť požadovanú hodnotu.

Používanie OFFSET

OFFSET ideálny pre typické v porovnaní s predchádzajúcimi typmi výpočtov potrebných na zodpovedanie obchodnej otázky popísanej vyššie, pretože nám umožňuje vykonať relatívny pohyb. Náš prvý pokus môže byť:

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

S týmto výrazom sa toho veľa deje. Použili sme ADDCOLUMNS na rozbalenie tabuľky spred a stĺpcom s názvom PreviousColorSales. Obsah tohto stĺpca je nastavený na hodnotu CurrentYearSales, ktorá je SUM(FactInternetSales[SalesAmount]) pre predchádzajúcu farbu (načítaná pomocou OFFSET).

Výsledok je:

Farba KalendárnyRok CurrentYearSales (AktuálnyPredajRoku) PreviousColorSales
"Black" (Čierna) 2017 393885
"Black" (Čierna) 2018 1818835 393885
"Black" (Čierna) 2019 3981638 1818835
"Black" (Čierna) 2020 2644054 3981638
"Modrá" 2019 994448 2644054
"Modrá" 2020 1284648 994448
"Multi" 2019 48622 1284648
"Multi" 2020 57849 48622
"NA" 2019 207822 57849
"NA" 2020 227295 207822
"Red" (červená) 2017 2961198 227295
"Red" (červená) 2018 3686935 2961198
"Red" (červená) 2019 900175 3686935
"Red" (červená) 2020 176022 900175
"Strieborné" 2017 326399 176022
"Strieborné" 2018 750026 326399
"Strieborné" 2019 2165176 750026
"Strieborné" 2020 1871788 2165176
"Biela" 2019 2517 1871788
"Biela" 2020 2589 2517
"Žltá" 2018 163071 2589
"Žltá" 2019 2072083 163071
"Žltá" 2020 2621602 2072083

Toto je o krok bližšie k nášmu cieľu, ale ak sa pozrieme pozorne, nezhoduje sa presne to, po čom ideme. Napríklad pre hodnotu [Silver, 2017] sa hodnota PreviousColorSales nastaví na hodnotu [Red, 2020].

Pridanie ORDERBY

Vyššie uvedená definícia je ekvivalentná:

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]
        )
    )

V tomto prípade volanie funkcie OFFSET používa ORDERBY na zoradenie tabuľky podľa hodnôt Color a CalendarYear vo vzostupnom poradí, ktoré určuje, čo sa považuje za predchádzajúci vrátený riadok.

Dôvodom, prečo sú tieto dva výsledky rovnocenné, je, že ORDERBY automaticky obsahuje všetky stĺpce zo vzťahu, ktoré nie sú v PARTITIONBY. Keďže PARTITIONBY nebol zadaný, ORDERBY sa nastaví na položky Color (Farba), CalendarYear (KalendárnyRok) a CurrentYearSales (AktuálnyPredajRoku). Keďže však páry Color a CalendarYear sú vo vzťahu jedinečné, pridanie stĺpca CurrentYearSales výsledok nezmení. Dokonca aj keby sme zadali farbu iba v ORDERBY, výsledky sú rovnaké, pretože calendarYear by sa pridali automaticky. Dôvodom je, že funkcia pridá toľko stĺpcov, koľko je potrebné na ORDERBY, aby sa zabezpečilo, že každý riadok bude môcť byť jednoznačne identifikovaný ORDERBY a PARTITIONBY stĺpcoch:

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]
        )
    )

Pridanie PARTITIONBY

Ak chcete takmer získame výsledok, ktorý sme získali po použití PARTITIONBY, ako je to znázornené v nasledujúcom výraze vypočítanej tabuľky:

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]
        )
    )

Všimnite si, že zadanie ORDERBY je tu voliteľné, pretože ORDERBY automaticky obsahuje všetky stĺpce zo vzťahu, ktoré nie sú zadané v PARTITIONBY. Takže nasledujúci výraz vráti rovnaké výsledky, pretože ORDERBY sa automaticky nastaví na stĺpce CalendarYear a CurrentYearSales:

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]
        )
    )

Nota

Hoci ORDERBY je automaticky nastavená na stĺpce CalendarYear a CurrentYearSales, nebude vám poskytnutá žiadna záruka v tom, v akom poradí sa tieto stĺpce pridajú. Ak je hodnota CurrentYearSales pridaná pred kalendárnyRok, výsledné poradie nie je vložené podľa očakávaní. Byť explicitný pri zadávaní ORDERBY a PARTITIONBY, aby sa predišlo nejasnostiam a neočakávaným výsledkom.

Oba výrazy vrátia výsledok, ktorý nasleduje:

Farba KalendárnyRok CurrentYearSales (AktuálnyPredajRoku) PreviousYearSalesForSameColor
"Black" (Čierna) 2017 393885
"Black" (Čierna) 2018 1818835 393885
"Black" (Čierna) 2019 3981638 1818835
"Black" (Čierna) 2020 2644054 3981638
"Modrá" 2019 994448
"Modrá" 2020 1284648 994448
"Multi" 2019 48622
"Multi" 2020 57849 48622
"NA" 2019 207822
"NA" 2020 227295 207822
"Red" (červená) 2017 2961198
"Red" (červená) 2018 3686935 2961198
"Red" (červená) 2019 900175 3686935
"Red" (červená) 2020 176022 900175
"Strieborné" 2017 326399
"Strieborné" 2018 750026 326399
"Strieborné" 2019 2165176 750026
"Strieborné" 2020 1871788 2165176
"Biela" 2019 2517
"Biela" 2020 2589 2517
"Žltá" 2018 163071
"Žltá" 2019 2072083 163071
"Žltá" 2020 2621602 2072083

Ako môžete vidieť v tejto tabuľke, stĺpec PreviousYearSalesForSameColor zobrazuje predaj za predchádzajúci rok pre rovnakú farbu. Pre [Červená, 2020] vráti predaj pre [Červená, 2019] a tak ďalej. Ak neexistuje žiadny predchádzajúci rok, napríklad v prípade [Červená, 2017], nevráti sa žiadna hodnota.

PARTITIONBY si môžete predstaviť ako spôsob, ako rozdeliť tabuľku na časti, v ktorých sa má vykonať výpočet OFFSET. V príklade uvedenom vyššie je tabuľka rozdelená do počtu častí, v ktorých sú farby, pričom jedna je pre každú farbu. Potom sa v každej časti vypočíta OFFSET zoradí podľa stĺpca KalendárnyRok.

Z vizuálneho prehľadu sa deje toto:

tabuľka zobrazujúca OFFSET podľa kalendárneho roka

Po prvé, výsledkom volania funkcie PARTITIONBY je rozdelenie tabuľky na časti, po jednom pre každú farbu. Toto je znázornené svetlomodrými poliami na obrázku tabuľky. Potom ORDERBY uistite sa, že každá časť je zoradená podľa stĺpca KalendárnyRok (znázornená oranžovými šípkami). Nakoniec v každej zoradenej časti nájde OFFSET nad ním riadok a vráti túto hodnotu v stĺpci PreviousYearSalesForSameColor. Keďže pre každý prvý riadok v každej časti neexistuje v tej istej časti žiadny predchádzajúci riadok, výsledok v tomto riadku pre stĺpec PreviousYearSalesForSameColor je prázdny.

Ak chceme dosiahnuť konečný výsledok, stačí odčítať hodnotu CurrentYearSales od predaja za predchádzajúci rok pre rovnakú farbu, ktorú vrátila výzva na OFFSET. Keďže nechceme zobrazovať predaj za predchádzajúci rok pre rovnakú farbu, ale len v aktuálnom roku predaja a v roku oproti predošlému rozdielu. Tu je finálny výraz vypočítanej tabuľky:

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]
        )
    )

Tu je výsledok tohto výrazu:

Farba KalendárnyRok CurrentYearSales (AktuálnyPredajRoku) YoYSalesForSameColor
"Black" (Čierna) 2017 393885 393885
"Black" (Čierna) 2018 1818835 1424950
"Black" (Čierna) 2019 3981638 2162803
"Black" (Čierna) 2020 2644054 -1337584
"Modrá" 2019 994448 994448
"Modrá" 2020 1284648 290200
"Multi" 2019 48622 48622
"Multi" 2020 57849 9227
"NA" 2019 207822 207822
"NA" 2020 227295 19473
"Red" (červená) 2017 2961198 2961198
"Red" (červená) 2018 3686935 725737
"Red" (červená) 2019 900175 -2786760
"Red" (červená) 2020 176022 -724153
"Strieborné" 2017 326399 326399
"Strieborné" 2018 750026 423627
"Strieborné" 2019 2165176 1415150
"Strieborné" 2020 1871788 -293388
"Biela" 2019 2517 2517
"Biela" 2020 2589 72
"Žltá" 2018 163071 163071
"Žltá" 2019 2072083 1909012
"Žltá" 2020 2621602 549519

Používanie MATCHBY

Možno ste si všimli, že sme vôbec neurčili MATCHBY. V tomto prípade to nie je potrebné. Stĺpce v ORDERBY a PARTITIONBY (pokiaľ boli zadané v príkladoch vyššie) stačia na jedinečnú identifikáciu každého riadka. Keďže sme neurčili MATCHBY, stĺpce zadané v ORDERBY a PARTITIONBY sa používajú na jedinečnú identifikáciu každého riadka, aby ich bolo možné porovnať a povoliť OFFSET dávať zmysluplný výsledok. Ak stĺpce v ORDERBY a PARTITIONBY nemôžu jednoznačne identifikovať každý riadok, do klauzuly ORDERBY môžu byť pridané ďalšie stĺpce, ak tieto dodatočné stĺpce umožňujú jedinečnú identifikáciu každého riadka. Ak to nie je možné, vráti sa chyba. V poslednom prípade môže špecifikácia MATCHBY pomôcť vyriešiť chybu.

Ak je zadaná hodnota MATCHBY, stĺpce v MATCHBY a PARTITIONBY sa použijú na jedinečnú identifikáciu každého riadka. Ak to nie je možné, vráti sa chyba. Dokonca aj keď MATCHBY nie je povinné, zvážte explicitné zadanie MATCHBY, aby ste sa vyhli nejasnostiam.

Pokračujeme v príkladoch uvedených vyššie a tu je posledný výraz:

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]
        )
    )

Ak chceme explicitne určiť, ako majú byť riadky jednoznačne identifikované, môžeme zadať MATCHBY tak, ako je to znázornené v nasledujúcom ekvivalentnom výraze:

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]
        )
    )

Keďže je zadaná MATCHBY, na jedinečnú identifikáciu riadkov sa používajú stĺpce zadané v MATCHBY, ako aj v PARTITIONBY. Keďže hodnota Color je zadaná v MATCHBY aj PARTITIONBY, nasledujúci výraz je ekvivalentný predchádzajúcemu výrazu:

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]
        )
    )

Keďže špecifikovanie MATCHBY nie je v doteraz zobrazených príkladoch potrebné, pozrime sa na trochu iný príklad, ktorý si vyžaduje MATCHBY. V tomto prípade máme k dispozícii zoznam riadkov objednávok. Každý riadok predstavuje riadok objednávky pre objednávku. Objednávka môže mať viacero riadkov objednávky a riadok objednávky 1 sa zobrazí v mnohých objednávkach. Navyše pre každý riadok objednávky máme kód ProductKey a SalesAmount (ObjemPredaja). Ukážka relevantných stĺpcov v tabuľke vyzerá takto:

SalesOrderNumber (ČísloPredajnejObjednávky) SalesOrderLineNumber (ČísloRiadkaPredajnejObjednávky) ProductKey (KódProduktu) SalesAmount (ObjemPredaja)
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

Všimnite si, že na jedinečnú identifikáciu riadkov sa vyžadujú obe možnosti ČísloPredajnejObjednávky a ČísloRiadkaPredajnejObjednávky.

Pre každú objednávku chceme vrátiť predchádzajúcu čiastku predaja toho istého produktu (reprezentovanú kódom ProductKey) zoradeného podľa objem predaja v zostupnom poradí. Nasledujúci výraz nebude fungovať, pretože vo funkcii vRelation môže existovať potenciálne viacero riadkov, pretože sa odovzdajú do OFFSET:

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

Tento výraz vráti chybu: "OFFSETrelačný parameter môže mať duplicitné riadky, čo nie je povolené."

Aby tento výraz fungoval, MATCHBY musí byť zadaný a musí obsahovať všetky stĺpce, ktoré jednoznačne definujú riadok. MATCHBY je tu potrebné, pretože vzťah FactInternetSales neobsahuje žiadne explicitné kľúče ani jedinečné stĺpce. Stĺpce SalesOrderNumber (ČísloPredajnejObjednávky) a SalesOrderLineNumber (ČísloRiadkaPredajnejObjednávky) však spoločne tvoria zložený kľúč, kde je ich existencia spolu jedinečná vo vzťahu, a preto dokážu jednoznačne identifikovať každý riadok. Stačí zadať iba zadanie hodnôt ČísloPredajnejObjednávky alebo ČísloRiadkaPredajnejObjednávky, pretože oba stĺpce obsahujú opakujúce sa hodnoty. Tento problém vyrieši nasledujúci výraz:

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

Tento výraz totiž vráti výsledky, ktoré nasleduje:

SalesOrderNumber (ČísloPredajnejObjednávky) SalesOrderLineNumber (ČísloRiadkaPredajnejObjednávky) ProductKey (KódProduktu) SalesAmount (ObjemPredaja) Predchádzajúca čiastka predaja
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