Professional Documents
Culture Documents
Jeffrey Wang
Engineering Manager
Microsoft Power BI
jewang@microsoft.com
About me
• Started my BI career in 2002 soon after the dot-com bubble burst.
• Joined Microsoft in 2004 and stayed in BI engine ever since.
• Currently on the Desktop team in charge of the DAX engine.
• On the committee which invented DAX.
How do users use DAX in Power BI?
• Measures
• Calculated columns
• Calculated tables
• Row level security
Agenda
• Learn how DAX measures work
• Deep dive into filter context
• Make my measures return correct results
• Make my measures run fast
Filter Context
Row Context and Filter Context
• Row Context
• Calculated columns
• RLS
• Iteration functions
• Filter Context
• Power BI visuals
• Excel pivot tables
• Calculate functions
Filter contexts
C1 C2 C3 C4 C5 C6 C3 C4 C1 C5 C7 C1 C8 C9
Filter Context
Filters in filter
context apply to
leaf nodes
How Does Filter Context Work?
Calculate(SumX(Filter(FactSales, [SalesQuantity] > 1000), [SalesAmount]), Date[Year] = 2011)
Order of operations
Sales Product
Date Product Key Product Key
Month Amount
Year Cost
• [Profit Margin] =
(Sum(Sales[Amount]) – Sum(Sales[Cost])) / Sum(Sales[Amount])
• Calculate([Profit Margin], 'Product'[Name] = "P1")
DAX functions that work with
filter context
DAX was inspired by existing programming
languages
• Excel formulas – math and trigonometry, statistical, date/time, text,
logical, information, financial
• SQL – relational algebra operations
• MDX – measures, implicit join
DAX functions from Excel
• +, -, *, /, ^, =, >, <, >=, <=, <>, &, DateValue, Day, EDate, EOMonth, Hour, Minute,
Month, Now, Second, Time, TimeValue, Today, Weekday, WeekNum, Year,
YearFrac, Date, IsBlank, IsError, IsLogical, IsNonText, IsNumber, IsText, IsEven,
IsOdd, And, False, If, IfError, Not, Or, Switch, True, Abs, Ceiling, ISO.Ceiling, Exp,
Fact, Floor, Int, Ln, Log, Log10, Mod, MRound, Pi, Power, Quotient, Rand,
RandBetween, Round, RoundDown, RoundUp, Sign, Sqrt, Trunc, Acos, Acosh, Acot,
Acoth, Asin, Asinh, Atan, Atanh, Combin, Cos, Cosh, Cot, Coth, Degrees, Even, Odd,
Permut, Radians, Sin, Sinh, SqrtPi, Tan, Tanh, Chisq.Dist, Chisq.Dist.Rt, Chisq.Inv,
Chisq.Inv.Rt, Combina, Confidence.Norm, Confidence.T, Expon.Dist, GCD, LCM,
Norm.Dist, Norm.Inv, Norm.S.Dist, Norm.S.Inv, Poisson.Dist, Beta.Dist, Beta.Inv,
T.Dist.2T, T.Dist, T.Dist.Rt, T.Inv.2T, T.Inv, Blank, Concatenate, Exact, Find, Fixed, Left,
Len, Lower, Mid, Replace, Rept, Right, Search, Substitute, Format, Trim, Upper,
Value, Unicode, Unichar, XNPV, XIRR
DAX functions inspired by SQL
• Selection: Filter, IN, ContainsRow
• TopN: TopN, Sample, TopNSkip
• Projection/Rename: SelectColumns, AddColumns
• GroupBy – Distinct, Values, Summarize, GroupBy
• Aggregation functions: IsEmpty, ConcatenateX, Sum, SumX, Average, AverageA, AverageX, Count,
CountRows, CountA, CountAX, CountX, CountBlank, DistinctCount, DistinctCountNoBlank, Max, MaxX, MaxA,
Median, MedianX, Min, MinX, MinA, Percentile.Exc, Percentile.Inc, PercentileX.Exc, PercentileX.Inc, Rank.EQ,
RankX, Stdev.S, StdevX.S, StdevX.P, Stdev.P, Var.S, VarX.S, VarX.P, Var.P, Product, ProductX, Geomean,
GeomeanX, CurrentGroup
• Joins: CrossJoin, Generate, GenerateAll, NaturalLeftOuterJoin, NaturalInnerJoin, FullOuterJoin
• Set functions: Union, Intersect, Except
• Table construction:{}, Row, DataTable, GenerateSeries
• Fetch column value: Related, LookupValue
• Hierarchical functions: Path, PathItem, PathItemReverse, PathLength, PathContains
DAX functions inspired by MDX
• Filter context functions: IsCrossFiltered, HasOneValue, IsFiltered, HasOneFilter,
RemoveFilters, All, AllExcept, AllNoBlankRow, AllSelected, Calculate, CalculateTable,
Filters, Values, SelectedValue, TreatAs, UseRelationship, CrossFilter, KeepFilters,
IsInScope, NonVisual
• BI query functions: SummarizeColumns, Rollup, RollupGroup, RollupAddIsSubtotal,
RollupIsSubtotal, IsSubtotal, Ignore, AddMissingItems
• Time intelligence functions: DateAdd, FirstDate, LastDate, FirstNonBlank, LastNonBlank,
StartOfMonth, StartOfQuarter, StartOfYear, EndOfMonth, EndOfQuarter, EndOfYear,
DatesBetween, DatesInPeriod, ParallelPeriod, PreviousDay, PreviousMonth,
PreviousQuater, PreviousYear, NextDay, NextMonth, NextQuarter, NextYear, DatesMTD,
DatesQTD, DatesYTD, SamePeriodLastYear, TotalMTD, TotalQTD, TotalYTD,
OpeningBalanceMonth, OpeningBalanceQuarter, OpeningBalanceYear,
ClosingBalanceMonth, ClosingBalanceQuarter, ClosingBalanceYear
Convert Row Context to Filter Context
• Calculate/CalculateTable
• Convert all rows in row context into filters in filter context
• Add new filters
• Remove filters
• Replace existing filters
• [measure] := <expression> is actually Calculate(<expression>)
• All rows have already been converted to filters before <expression> is
evaluated
• 'Table'[Column] does not work at the top level of a measure expression
• Filter is an iteration function. It doesn’t change filter contexts.
Common DAX patterns that may
produce unexpected results
Set simple filters
• The following two ways of setting filters are different:
1. Calculate(Sum('Sales'[Sales Amount]), Geography[Country] = "United States")
2. Calculate(Sum('Sales'[Sales Amount]), Filter(Geography, [Country] = "United States"))
• Option 1 is equivalent to
1.1. Calculate(Sum('Sales'[Sales Amount]), Filter(All(Geography[Country]), [Country] = "United States"))
YTD Sales =
Calculate(
[Total Sales],
Filter(All('Date'[Date]), Year([Date]) = Year([Current Date]) && [Date] <= [Current Date])
)
• Solution: Use variables to store measure values in the correct context
YTD Sales =
Var vCurrentDate = [Current Date]
Return
Calculate(
[Total Sales],
Filter(All('Date'[Date]), Year([Date]) = Year(vCurrentDate) && [Date] <= vCurrentDate)
)
Time Intelligence Functions
Excel date/time functions vs. DAX time
intelligence functions
• DAX stores dates as sequential numbers representing the number of days starting from 12/30/1899.
• Example: convert number of seconds into DateTime:
• Date(1899, 12, 30) + <number of seconds> / (24 * 60 * 60)
• Time(0, 0, <number of seconds>) has limitations
• Arithmetic operators and Excel functions operate on a single date/time value.
• Extract components from a date/time value
• Construct a date/time value from parts
• Convert a text value to a date/time value
• Shift a single date
• Often used to add calculated columns
• Can be done in M as well
• Don't use DAX in M editor
• DAX time intelligence functions operate on a filtered date column.
• Shift selected continuous dates
• Primarily used in measures
Excel date/time functions vs. DAX time
intelligence functions (Examples)
Scenario Right way Wrong way
7 days ago from today Today() - 7 DateAdd(Today(), -7, DAY)
1 month ago from today EDate(Today(), -1) DateAdd(Today(), -1, MONTH)
the last day of this month EOMonth(Today(), 0) EndOfMonth(Today())
the first day of this month Today() – Day(Today()) + 1 StartOfMonth(Today())
year to date sales TotalYTD, flexible Filter(…, [Date] <= Values([Date]) &&
[Date] >= Date(Year(Values([Date])), 1, 1))
DAX time intelligence function example:
SamePeriodLastYear
2012 1 04/01/2012
X
2012 2 04/02/2012
2012 3 ...
06/30/2012
2012 4
2013 1
2013 2
2013 3
2013 4
Evaluation Context
DAX time intelligence functions shift
continuous dates
• Common error message
MdxScript(Model) (X, XX) Calculation error in measure 'XXX'[X]: Function
'DATEADD' only works with contiguous date selections.
• Examples
1. Multi-selection of years
2. Bi-directional cross-filtering to the Date table
• Time intelligence functions work on filtered date column.
Hidden date tables and DAX dot notation
• PowerBI automatically creates a hidden data table for each date/time
column
• A uni-direction relationship is created between the visible date/time
column and the hidden date table
• Users can access the columns in a hidden date table using DAX dot
notation through the visible date/time column
• [Order Date].[Date] is equivalent to Related('Hidden Table'[Date])
• [Order Date].[Year] is equivalent to Related('Hidden Table'[Year])
Common DAX patterns that
produce slow queries
DistinctCount with changing filters
• Calculate(DistinctCount('Sales'[CustomerKey]), Except(All('Product'),
'Product’))
• Calculate(DistinctCount('Sales'[CustomerKey]),
Filter(Values('Product'[Standard Cost]), [Standard Cost] > 100))
Avoid dense measures combined with
columns from different dimension tables
• BLANK value is your friend in BI queries.
• Examples of dense measures:
• [measure] = 1
• [measure] = Count('Sales'[ProductKey]) + 0
• [measure] = If ([Total Sales] <> 0, [Gross Margin] / [Total Sales], 0)
• The combination of many columns from different dimension tables
and a dense measure is a leading cause of out-of-memory errors.
Replace multiple instances of the same
measure by a variable
• [YoY growth] = Divide([CY Sales] – [LY Sales], [LY Sales])