Förstå funktionerna ORDERBY, PARTITIONBY, andMATCHBY
Funktionerna ORDERBY, PARTITIONBY, andMATCHBY i DAX är specialfunktioner som bara kan användas tillsammans med DAXWindow funktioner: INDEX, OFFSET, WINDOW, RANK, ROWNUMBER.
Att förstå ORDERBY, PARTITIONBY, andMATCHBY är viktigt för att kunna använda Window-funktionerna. Exemplen här använder OFFSET, men gäller på samma sätt för andra Window funktioner.
Scenario
Låt oss börja med ett exempel som inte använder Window funktioner på all. Nedan visas en tabell som returnerar total försäljning, per färg, per calendaryear. Det finns flera sätt att define den här tabellen, men eftersom vi vill förstå vad som händer i DAXanvänder vi en kalkylerad tabell. Här är tabelluttrycket:
BasicTable =
SUMMARIZECOLUMNS (
DimProduct[Color],
DimDate[CalendarYear],
"CurrentYearSales", ROUND ( SUM ( FactInternetSales[SalesAmount] ), 0 )
)
Du ser att det här beräknade tabelluttrycket använder SUMMARIZECOLUMNS för att calculateSUM för kolumnen SalesAmount i tabellen FactInternetSales, efter kolumnen Färg från tabellen DimProduct, and kolumnen CalendarYear från tabellen DimDate. Här är resultatet:
Färg | Kalenderår | FörsäljningDettaÅr |
---|---|---|
"Svart" | 2017 | 393885 |
"Svart" | 2018 | 1818835 |
"Svart" | 2019 | 3981638 |
"Svart" | 2020 | 2644054 |
"Blå" | 2019 | 994448 |
"Blå" | 2020 | 1284648 |
"Flera" | 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 |
"Silver" | 2017 | 326399 |
"Silver" | 2018 | 750026 |
Silver | 2019 | 2165176 |
Silver | 2020 | 1871788 |
"Vit" | 2019 | 2517 |
Vit | 2020 | 2589 |
"Gul" | 2018 | 163071 |
"Gul" | 2019 | 2072083 |
"Gul" | 2020 | 2621602 |
Now, låt oss föreställa oss att vi försöker lösa affärsfrågan om att beräkna skillnaden i försäljning, year- över -year för varje färg. I själva verket behöver vi hitta ett sätt att subtrahera find försäljning för samma färg i previousyearand från försäljningen i den aktuella yeari sammanhanget. För kombinationen [Red, 2019] letar vi till exempel efter försäljning för [Red, 2018]. När vi har det kan vi sedan subtrahera det från den aktuella försäljningen and och returnera den nödvändiga value.
Använda OFFSET
OFFSET är perfekt för de typiska -previous--beräkningar som krävs för att besvara affärsfrågan som beskrivs ovan, eftersom det tillåter oss att göra en relativ rörelse. Vårt first-försök kan vara:
1stAttempt =
VAR vRelation = SUMMARIZECOLUMNS (
DimProduct[Color],
DimDate[CalendarYear],
"CurrentYearSales", ROUND ( SUM ( FactInternetSales[SalesAmount] ), 0 )
)
RETURN
ADDCOLUMNS (
vRelation,
"PreviousColorSales",
SELECTCOLUMNS (
OFFSET (
-1,
vRelation
),
[CurrentYearSales]
)
)
Mycket händer med det här uttrycket. Vi använde ADDCOLUMNS till expand den tidigare tabellen med en kolumn som heter PreviousColorSales. Innehållet i kolumnen är inställt på CurrentYearSales, som är SUM(FactInternetSales[SalesAmount]), för färgen previous (hämtas med OFFSET).
Resultatet är:
Färg | Kalenderår | FörsäljningFörNuvarandeÅr | FöregåendeFärgFörsäljningar |
---|---|---|---|
"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 |
"Silver" | 2017 | 326399 | 176022 |
Silver | 2018 | 750026 | 326399 |
"Silver" | 2019 | 2165176 | 750026 |
"Silver" | 2020 | 1871788 | 2165176 |
Vit | 2019 | 2517 | 1871788 |
"Vit" | 2020 | 2589 | 2517 |
"Gul" | 2018 | 163071 | 2589 |
"Gul" | 2019 | 2072083 | 163071 |
"Gul" | 2020 | 2621602 | 2072083 |
Detta är ett steg närmare vårt mål, men if vi tittar noga matchar det inte exakt vad vi är efter. Till exempel för [Silver, 2017] är PreviousColorSales inställt på [Red, 2020].
Lägga till ORDERBY
Definitionen ovan motsvarar:
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 det här fallet använder anropet till OFFSETORDERBY för att sortera tabellen efter Color and CalendarYear i stigande ordning, vilket fastställer vilken som anses vara den previous rad som returneras.
Anledningen till att dessa två resultat är likvärdiga är att ORDERBY automatiskt containsall kolumner från relationen som inte finns i PARTITIONBY. Eftersom PARTITIONBY inte har specificerats, är ORDERBY satt till Color, CalendarYear, and CurrentYearSales. Men eftersom paren Color and CalendarYear i relationen är unika ändrar inte resultatet att lägga till CurrentYearSales. I fact, evenif skulle vi bara ange Färg i ORDERBY, blev resultatet detsamma eftersom CalendarYear skulle automatiskt läggas till. Det beror på att funktionen lägger till så många kolumner som behövs till ORDERBY för att säkerställa att varje rad kan identifieras unikt av ORDERBYandPARTITIONBY kolumnerna.
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]
)
)
Lägga till PARTITIONBY
Now, för att nästan få det resultat vi är efter kan vi använda PARTITIONBY, enligt följande beräknade tabelluttryck:
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]
)
)
Observera att det är valfritt att ange ORDERBY här eftersom ORDERBY automatiskt containsall kolumnerna från relationen som inte anges i PARTITIONBY. Följande uttryck returnerar alltså samma resultat eftersom ORDERBY anges till CalendarYear and CurrentYearSales automatiskt:
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]
)
)
Not
Även om ORDERBY anges till CalendarYear and CurrentYearSales automatiskt, ges ingen garanti för vilken ordning de ska läggas till. If CurrentYearSales läggs till före CalendarYear, och den resulterande ordningen är inte i linje med vad som förväntades. Var explicit när du anger ORDERBYandPARTITIONBY för att undvika förvirring and oväntade resultat.
Båda uttrycken returnerar det resultat vi är efter:
Färg | Kalenderår | FörsäljningNuvarandeÅr | FöregåendeÅrsFörsäljningFörSammaFärg |
---|---|---|---|
"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 | |
Många | 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 |
Silver | 2017 | 326399 | |
Silver | 2018 | 750026 | 326399 |
"Silver" | 2019 | 2165176 | 750026 |
"Silver" | 2020 | 1871788 | 2165176 |
Vit | 2019 | 2517 | |
"Vit" | 2020 | 2589 | 2517 |
"Gul" | 2018 | 163071 | |
"Gul" | 2019 | 2072083 | 163071 |
"Gul" | 2020 | 2621602 | 2072083 |
Som du ser i den här tabellen visar kolumnen PreviousYearSalesForSameColor försäljningen för previousyear för samma färg. För [Red, 2020] returnerar den försäljningen för [Red, 2019], and och så vidare. If det finns ingen previousyear, till exempel när det gäller [Red, 2017], returneras inga value.
Du kan se PARTITIONBY som ett sätt att divide tabellen i delar där du kan köra OFFSET-beräkningen. I exemplet ovan är tabellen uppdelad i så många delar som det finns färger, en för varje färg. Sedan beräknas OFFSET inom varje del och sorteras efter CalendarYear.
Visuellt är det här:
Firstresulterar anropet till PARTITIONBY i att tabellen blir uppdelad i sektioner, en för varje färg. Detta representeras av de ljusblå rutorna i tabellbilden. Nextkontrollerar ORDERBY att varje del sorteras efter CalendarYear (representeras av de orangea pilarna). Slutligen, inom varje sorterad del, för varje rad, hittar OFFSET raden ovanför den and returnerar den value i kolumnen PreviousYearSalesForSameColor. Eftersom det för varje first rad i varje del inte finns någon previous rad i samma del är resultatet i raden för kolumnen PreviousYearSalesForSameColor tomt.
För att uppnå det slutliga resultatet behöver vi bara dra av CurrentYearSales från försäljningen för previousyear för samma färg som returneras av anropet till OFFSET. Eftersom vi är not intresserade av att visa previousyear försäljning för samma färg, men bara i den aktuella year försäljning andyear över year skillnad. Här är det slutliga beräknade tabelluttrycket:
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 här är resultatet av uttrycket:
Färg | Kalenderår | FörsäljningFörNuvarandeÅr | 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 |
Flera | 2019 | 48622 | 48622 |
Flera | 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 |
Silver | 2017 | 326399 | 326399 |
Silver | 2018 | 750026 | 423627 |
"Silver" | 2019 | 2165176 | 1415150 |
Silver | 2020 | 1871788 | -293388 |
Vit | 2019 | 2517 | 2517 |
"Vit" | 2020 | 2589 | 72 |
"Gul" | 2018 | 163071 | 163071 |
"Gul" | 2019 | 2072083 | 1909012 |
"Gul" | 2020 | 2621602 | 549519 |
Använda MATCHBY
Du kanske har märkt att vi inte angav MATCHBY på all. I det här fallet är det inte nödvändigt. Kolumnerna i ORDERBYandPARTITIONBY (i den mån de angavs i exemplen ovan) räcker för att unikt identifiera varje rad. Eftersom vi inte angav MATCHBYanvänds de kolumner som anges i ORDERBYandPARTITIONBY för att unikt identifiera varje rad så att de kan jämföras för att aktivera OFFSET för att ge ett meningsfullt resultat. If kolumnerna i ORDERBYandPARTITIONBY inte kan identifiera varje rad unikt kan ytterligare kolumner läggas till i ORDERBY-satsen if dessa extra kolumner gör att varje rad kan identifieras unikt. If om det är not möjligt returneras en error. I det här last fallet kan det hjälpa att ange MATCHBY för att lösa error.
If MATCHBY anges används kolumnerna i MATCHBYandPARTITIONBY för att unikt identifiera varje rad. If om det är not möjligt, returneras en error. Even if MATCHBY är inte nödvändigt, så du bör uttryckligen ange MATCHBY för att undvika förvirring.
Fortsätt från exemplen ovan, här är last-uttrycket:
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 vill vara tydliga med hur rader ska identifieras unikt kan vi ange MATCHBY som visas i följande motsvarande uttryck:
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]
)
)
Eftersom MATCHBY har angetts används både de kolumner som anges i MATCHBY och i PARTITIONBY för att unikt identifiera rader. Eftersom Color anges i både MATCHBY,andochPARTITIONBY, motsvarar följande uttryck uttrycket 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]
)
)
Eftersom det inte är nödvändigt att ange MATCHBY i de exempel som vi har tittat på hittills ska vi titta på ett lite annorlunda exempel som kräver MATCHBY. I det här fallet har vi en lista över orderrader. Varje rad representerar en orderrad för en order. En order kan ha flera orderrader and orderrad 1 visas på många beställningar. Dessutom har vi för varje orderrad en Produktnyckel and och ett Försäljningsbelopp. En sample av relevanta kolumner i tabellen ser ut så här:
Försäljningsordernummer | FörsäljningsorderRadsnummer | Produktnyckel | Försäljningsbelopp |
---|---|---|---|
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 |
Observera att SalesOrderNumber and SalesOrderLineNumber krävs för att unikt identifiera rader.
För varje order vill vi returnera previous försäljningsbeloppet för samma product (som representeras av ProductKey) sorterade efter SalesAmount i fallande ordning. Följande uttryck fungerar inte eftersom det potentiellt finns flera rader i vRelation när det skickas till OFFSET:
ThisExpressionFailsBecauseMATCHBYIsMissing =
ADDCOLUMNS (
FactInternetSales,
"Previous Sales Amount",
SELECTCOLUMNS (
OFFSET (
-1,
FactInternetSales,
ORDERBY ( FactInternetSales[SalesAmount], DESC ),
PARTITIONBY ( FactInternetSales[ProductKey] )
),
FactInternetSales[SalesAmount]
)
)
Det här uttrycket returnerar ett error: "OFFSETrelationsparameter kan ha dubbletter av rader, vilket inte är tillåtet."
För att det här uttrycket ska fungera måste MATCHBY anges and måste innehålla all kolumner som unikt define en rad. MATCHBY krävs här eftersom relationen FactInternetSales inte innehåller några explicita nycklar or unika kolumner. Kolumnerna SalesOrderNumber and och SalesOrderLineNumber bildar dock tillsammans en sammansatt nyckel, där deras existens tillsammans är unik i relationen and och därför kan dessa unikt identifiera varje rad. Det räcker inte att bara ange SalesOrderNumber or SalesOrderLineNumber eftersom båda kolumnerna innehåller upprepande values. Följande uttryck 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 det här uttrycket returnerar verkligen de resultat vi är efter:
Försäljningsordernummer | Försäljningsorderlinjenummer | Produktnyckel | Försäljningsbelopp | Previous försäljningsbelopp |
---|---|---|---|---|
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 |
Related innehåll
ORDERBY PARTITIONBY MATCHBY INDEX OFFSET WINDOW RANK ROWNUMBER