Sdílet prostřednictvím


Principy funkcí ORDERBY, PARTITIONBY, andMATCHBY

ORDERBY, PARTITIONBY, andMATCHBY funkce v DAX jsou speciální funkce, které lze použít pouze společně s funkcemi DAXWindow: INDEX, OFFSET, WINDOW, RANK, ROWNUMBER.

Pochopení ORDERBY, PARTITIONBY, andMATCHBY je důležité pro úspěšné použití funkcí Window. Zde uvedené příklady používají OFFSET, ale podobně platí i pro ostatní funkce Window.

Scénář

Začněme příkladem, který nepoužívá funkce Window na all. Níže je uvedena tabulka, která zobrazuje celkové prodeje pro každou barvu pro calendaryear. Existuje několik způsobů, jak tuto tabulku define vytvořit, ale protože nás zajímá, co se stane v DAX, použijeme tabulku se vzorcem. Tady je výraz tabulky:

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

Uvidíte, že tento výraz počítané tabulky používá SUMMARIZECOLUMNS k calculateSUM sloupce SalesAmount v tabulce FactInternetSales podle sloupce Color z tabulky DimProduct and sloupec CalendarYear z tabulky DimDate. Tady je výsledek:

Barva Kalendářní rok Prodeje za současný rok
"Černá" 2017 393885
"Černá" 2018 1818835
"Černá" 2019 3981638
"Černá" 2020 2644054
"Modrá" 2019 994448
"Modrá" 2020 1284648
Více 2019 48622
Multi 2020 57849
"NA" 2019 207822
NA 2020 227295
"Červená" 2017 2961198
"Červená" 2018 3686935
"Červená" 2019 900175
"Červená" 2020 176022
"Silver" 2017 326399
"Silver" 2018 750026
stříbro 2019 2165176
Stříbrný 2020 1871788
Bílá 2019 2517
"Bílá" 2020 2589
"Žlutá" 2018 163071
"Žlutá" 2019 2072083
"Žlutá" 2020 2621602

Now, představme si, že se snažíme vyřešit obchodní otázku výpočtu rozdílu v prodeji, year-over-year pro každou barvu. V podstatě potřebujeme způsob, jak find prodej pro stejnou barvu v previousyearand odečíst od prodeje v aktuálním yearv kontextu. Například pro kombinaci [Red, 2019] hledáme prodej pro [Red, 2018]. Jakmile to máme, můžeme to odečíst od aktuálního prodeje and a vrátit požadované value.

Použití OFFSET

OFFSET je ideální pro typické porovnání s previous typy výpočtů potřebnými k zodpovězení výše popsané obchodní otázky, protože nám umožňuje provádět relativní pohyb. Naším first pokusem může být:

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

Tento výraz se hodně používá. Použili jsme ADDCOLUMNS k expand tabulku z dřívějška s názvem PreviousColorSales. Obsah tohoto sloupce je nastaven na CurrentYearSales, což odpovídá SUM(FactInternetSales[SalesAmount]), pro barvu previous (načtenou pomocí OFFSET).

Výsledkem je:

Barva Kalendářní rok Prodeje tohoto roku Prodej předchozích barev
"Černá" 2017 393885
"Černá" 2018 1818835 393885
"Černá" 2019 3981638 1818835
"Černá" 2020 2644054 3981638
"Modrá" 2019 994448 2644054
"Modrá" 2020 1284648 994448
Mult 2019 48622 1284648
Více 2020 57849 48622
"NA" 2019 207822 57849
"NA" 2020 227295 207822
"Červená" 2017 2961198 227295
"Červená" 2018 3686935 2961198
"Červená" 2019 900175 3686935
"Červená" 2020 176022 900175
"Silver" 2017 326399 176022
"Silver" 2018 750026 326399
"Silver" 2019 2165176 750026
"Silver" 2020 1871788 2165176
Bílá 2019 2517 1871788
Bílá 2020 2589 2517
"Žlutá" 2018 163071 2589
"Žlutá" 2019 2072083 163071
"Žlutá" 2020 2621602 2072083

Toto je jeden krok blíž k našemu cíli, ale if podíváme se pozorně, že neodpovídá přesně tomu, co jsme poté. Například pro [Silver, 2017] PreviousColorSales je nastaven na [Red, 2020].

Přidání ORDERBY

Výše uvedená definice odpovídá:

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 případě volání OFFSET používá ORDERBY k seřazení tabulky podle barvy and CalendarYear vzestupně, což určuje, co se považuje za vrácený řádek previous.

Důvod, proč jsou tyto dva výsledky ekvivalentní, je, že ORDERBY automaticky containsall sloupce z relace, které nejsou v PARTITIONBY. Vzhledem k tomu, že PARTITIONBY nebylo specifikováno, je ORDERBY nastavena na barvu, kalendářní rok, and aktuální prodej za rok. Vzhledem k tomu, že dvojice s barvou and v rámci CalendarYear v relaci jsou jedinečné, přidání CurrentYearSales nemění výsledek. V fact, evenif jsme zadali pouze barvu v ORDERBY, výsledky jsou stejné, protože CalendarYear by se automaticky přidal. Důvodem je to, že funkce přidá tolik sloupců, kolik je potřeba k ORDERBY, aby bylo zajištěno, že každý řádek může být jednoznačně identifikován ORDERBYandPARTITIONBY sloupci:

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

Přidání PARTITIONBY

Now téměř získat výsledek, který můžeme použít PARTITIONBY, jak je znázorněno v následujícím výrazu počítané tabulky:

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šimněte si, že zadání ORDERBY je zde volitelné, protože ORDERBY automaticky containsall sloupce z relace, které nejsou zadány v PARTITIONBY. Následující výraz tedy vrátí stejné výsledky, protože ORDERBY je nastavena na CalendarYear and CurrentYearSales automaticky:

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

Poznámka

I když je ORDERBY nastavena na CalendarYear and CurrentYearSales automaticky, není žádná záruka, pokud jde o pořadí, ve kterém budou přidány. If CurrentYearSales se přidá před CalendarYear, výsledné pořadí není v souladu s očekáváním. Být explicitní při zadávání ORDERBYandPARTITIONBY, aby nedocházelo k nejasnostem and neočekávané výsledky.

Oba výrazy vrátí výsledek, který hledáme.

Barva kalendářní rok Prodej za aktuální rok ProdejZaStejnouBarvuZMinuléhoRoku
"Černá" 2017 393885
"Černá" 2018 1818835 393885
"Černá" 2019 3981638 1818835
"Černá" 2020 2644054 3981638
"Modrá" 2019 994448
"Modrá" 2020 1284648 994448
Multi 2019 48622
Multi 2020 57849 48622
"NA" 2019 207822
"NA" 2020 227295 207822
"Červená" 2017 2961198
"Červená" 2018 3686935 2961198
"Červená" 2019 900175 3686935
"Červená" 2020 176022 900175
"Silver" 2017 326399
"Silver" 2018 750026 326399
"Silver" 2019 2165176 750026
"Silver" 2020 1871788 2165176
Bílá 2019 2517
Bílá 2020 2589 2517
"Žlutá" 2018 163071
"Žlutá" 2019 2072083 163071
"Žlutá" 2020 2621602 2072083

Jak vidíte v této tabulce, sloupec PreviousYearSalesForSameColor zobrazuje prodeje pro previousyear pro stejnou barvu. Pro [Red, 2020] vrátí prodej za [Red, 2019], and a podobně. If neexistuje žádná previousyear, například v případě [Red, 2017], nevrátí se žádná value.

PARTITIONBY si můžete představit jako způsob, jak divide tabulku do částí, ve kterých se má provést výpočet OFFSET. V předchozím příkladu je tabulka rozdělena na tolik částí, kolik je barev, jedna pro každou barvu. Pak se v rámci každé části vypočítá OFFSET a seřadí podle kalendářního roku.

Pohledem na situaci je vidět toto:

tabulka zobrazující OFFSET podle CalendarYear

First, volání PARTITIONBY vede k tomu, že se tabulka rozdělí do částí, jedna pro každou barvu. Toto je reprezentováno světle modrými poli na obrázku tabulky. Next, ORDERBY zajistí, aby každá část byla seřazena podle CalendarYear (reprezentované oranžovými šipkami). Nakonec v každé seřazené části OFFSET najde řádek nad ním and vrátí value ve sloupci PreviousYearSalesForSameColor. Vzhledem k tomu, že pro každý first řádek v každé části není ve stejné části žádný řádek previous, je výsledek v tomto řádku pro sloupec PreviousYearSalesForSameColor prázdný.

K dosažení konečného výsledku musíme jednoduše odečíst prodeje v aktuálním roce od prodeje previousyear pro stejnou barvu, kterou vrací volání OFFSET. Vzhledem k tomu, že not zájem o zobrazení prodeje previousyear pro stejnou barvu, ale pouze v aktuálním year prodeji andyear oproti rozdílu year. Tady je konečný počítaný výraz tabulky:

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 zde je výsledek toho výpočtu:

Barva kalendářní rok Prodeje za tento rok YoYSalesForSameColor
"Černá" 2017 393885 393885
"Černá" 2018 1818835 1424950
"Černá" 2019 3981638 2162803
"Černá" 2020 2644054 -1337584
"Modrá" 2019 994448 994448
"Modrá" 2020 1284648 290200
"Více" 2019 48622 48622
Multi 2020 57849 9227
NA 2019 207822 207822
"NA" 2020 227295 19473
"Červená" 2017 2961198 2961198
"Červená" 2018 3686935 725737
"Červená" 2019 900175 -2786760
"Červená" 2020 176022 -724153
"Silver" 2017 326399 326399
"Silver" 2018 750026 423627
"Silver" 2019 2165176 1415150
"Silver" 2020 1871788 -293388
Bílá 2019 2517 2517
"Bílá" 2020 2589 72
"Žlutá" 2018 163071 163071
"Žlutá" 2019 2072083 1909012
"Žlutá" 2020 2621602 549519

Použití MATCHBY

Možná jste si všimli, že jsme nezadali MATCHBY v all. V tomto případě není nutné. Sloupce v ORDERBYandPARTITIONBY (pokud jsou uvedené v příkladech výše) stačí k jednoznačné identifikaci jednotlivých řádků. Vzhledem k tomu, že jsme nezadali MATCHBY, sloupce zadané v ORDERBYandPARTITIONBY slouží k jedinečné identifikaci jednotlivých řádků, aby bylo možné je porovnat, aby OFFSET poskytl smysluplný výsledek. If sloupce v ORDERBYandPARTITIONBY nemohou jednoznačně identifikovat jednotlivé řádky, do klauzule ORDERBY je možné přidat další sloupce, if tyto nadbytečné sloupce umožňují jedinečně identifikovat každý řádek. If je možné not, vrátí se error. V tomto last případě může určení MATCHBY pomoct vyřešit error.

If MATCHBY je zadán, sloupce v MATCHBYandPARTITIONBY slouží k jedinečné identifikaci jednotlivých řádků. If, to je not možné, je vráceno error. Even if MATCHBY není nutné, zvažte explicitní zadání MATCHBY, abyste se vyhnuli nejasnostem.

Pokračujeme z výše uvedených příkladů, tady je výraz 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 chceme explicitně určit, jak mají být řádky jednoznačně identifikovány, můžeme zadat MATCHBY, jak je znázorněno v následujícím ekvivalentním výrazu:

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

Vzhledem k tomu, že je zadán MATCHBY, oba sloupce zadané v MATCHBY i v PARTITIONBY slouží k jedinečné identifikaci řádků. Vzhledem k tomu, že v obou MATCHBYandPARTITIONBYje zadaná funkce Color, je následující výraz ekvivalentní výrazu previous:

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

Vzhledem k tomu, že určení MATCHBY není nutné v příkladech, na které jsme se zatím podívali, podívejme se na mírně jiný příklad, který vyžaduje MATCHBY. V tomto případě máme seznam řádků objednávek. Každý řádek představuje položku objednávky. Objednávka může mít více řádků objednávek and řádek objednávky 1 se zobrazí v mnoha objednávkách. Kromě toho pro každý řádek objednávky máme ProductKey and a SalesAmount. sample relevantních sloupců v tabulce vypadá takto:

ČísloObjednávkyProdeje ČísloŘádkuObjednávky Produktový klíč Částka prodeje
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 Kč
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šimněte si, že čísla SalesOrderNumber and a SalesOrderLineNumber jsou nutná k jednoznačné identifikaci řádků.

Pro každou objednávku chceme vrátit částku prodeje previous pro stejný product (představovaný kódem ProductKey), která je seřazena podle hodnoty prodeje v sestupném pořadí. Následující výraz nebude fungovat, protože ve vRelation jsou potenciálně více řádků, což se předává 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átí error: "OFFSETrelační parametr může mít duplicitní řádky, které nejsou povoleny."

Aby tento výraz fungoval, musí být MATCHBY zadán a and musí obsahovat all sloupce, které jednoznačně define řádek. MATCHBY se tady vyžaduje, protože relace FactInternetSales neobsahuje žádné explicitní klíče or jedinečných sloupců. Sloupce SalesOrderNumber and a SalesOrderLineNumber společně tvoří složený klíč, kde jejich společná existence je jedinečná ve vztahu and, a proto mohou jednoznačně identifikovat každý řádek. Nestačí pouze zadat SalesOrderNumber or a SalesOrderLineNumber, protože oba sloupce obsahují opakující se hodnoty values. Tento problém řeší následující 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]
            )
    )

And tento výraz skutečně vrací výsledky, o které se snažíme:

ČísloObjednávkyProdeje ČísloŘádkyObjednávky Produktový klíč Částka prodeje Previous Částka prodeje
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