在数据报表中常有一类需求是按照一定要求对数据进行排序,然后根据排序结果,获取前N个数据,例如,求总成绩排名前10的学生,求销售量最多的前3个产品等等。

在DAX中要实现该需求,通常是用的函数有两个,一个是TOPN,还有一个是RANKX。本文主要介绍TOPN的用法,其语法结构如下:

TOPN(<n_value>, <table>, <orderBy_expression>, [<order>[, <orderBy_expression>, [<order>]]…])

TOPN函数主要有3个参数组成:

  • <n_value>处需要填写一个返回的行数,也就是想要获取前多少个数据,即N值。可以是一个数字,也可以是一个返回单一数字的表达式。
  • < table>处指定从哪个表单中获取前N个数据,可以填写一个表单或者可以返回表单的表达式。
  • <orderBy_expression>处填写一个表达式,该表达式的返回结果将作为表单的排序依据。
  • < order>是一个可选项,如果填写0或者FALSE或者DESC,代表按照降序对表单进行排序;如果填写1或者TRUE或者ASC,则按照升序对表单进行排序。如果缺省则表示0,如果填写其他数值,则DAX会报错。

TOPN函数的返回结果是一个表单,也就是说,如果是单一的直接使用TOPN函数,只能通过创建一个计算表单来调用。如果是想在度量值或则计算列中使用TOPN函数,则必须作为其他函数的参数而进行使用。

说明:

  1. n_value这个地方如果填写的是正小数,则DAX会取小数点后一位,然后按照四舍五入规则转换成整数,来确定N值。 如果填写的是负数或者0,则返回空表单。
  2. 对于排序结果,如果有相同值,即排序序号相同,当这种数据符合前N的筛选条件时,TOPN函数会把相同值数据都作为结果进行返回。
  3. TOPN的输出结果属于无序排序,也就是说虽然会返回前N行数据,但是第一行中的排序列下数据可能并不是最大/最小值。

TOPN函数最常见的的应用场景是求前N个数据的总和,例如,求下图销售量前3的商品总和,就可以创建一个度量值利用SUMX函数和TOPN函数来进行。

TopN_Q_SUM =
SUMX (
    TOPN ( 3, SalesInfo, SalesInfo[Sales Volume], 0 ),
    SalesInfo[Sales Volume]
)

Series取前10个 如何取数据前10位数字_PowerBI

公式里面用了最基本常规的算法,可以看得TOPN函数按照原始表单的Sales Volume值对数据进行了排序,然后将数值最大的前三行数据组成一个表单返回给外围SUMX函数使用。

可以通过下面这个计算表更加清晰获得TOPN函数的计算结果。

Series取前10个 如何取数据前10位数字_Power BI_02


之所以要强调TOPN返回的表单结果是因为如果用TopN_Q_SUM这个度量值去创建表单,会造成一种错觉,以为获取的前N个数值有问题。如下图,Total处的统计值显示2000,按照理解应该是销售排名前三的销售量总和,但是单从这个表单看,前三产品的销售额分别是1000, 900,和700,其和并不等于2000。

Series取前10个 如何取数据前10位数字_DAX_03


之所以出现这个原因是因为在当前计算表中,TopN_Q_SUM的计算会受到Product这个筛选上下文的影响,例如当Product = Computers的时候,实际上是将原始表单进行了过滤,只保留了 Product = Computers的子表单,之后TOPN对改子表单中的Sales Volume进行了排序,获取了前3个最大值,之后经过SUMX进行了求和计算。

Series取前10个 如何取数据前10位数字_排序_04

由于TopN_Q_SUM的计算公式中表单参数直接填写的是当前SalesInfo表单,所以每次数据的计算都是依据被筛选上下文影响的整个SalesInfo表单来进行。

如果不按照Country列对Product进行分类,只是单纯的对每种产品销售量前3的数据进行汇总求和,则需要对TopN_Q_SUM函数进行修改,利用SUMMARIZE函数,将TOPN函数中的参数表单变成按照Product汇总过后的数据表,之后再进行计算即可。

TopN_Q_SUM =
SUMX (
    TOPN (
        3,
        SUMMARIZE (
            SalesInfo,
            SalesInfo[Product],
            "Volume", SUM ( SalesInfo[Sales Volume] )
        ),
        [Volume], 0
    ),
    [Volume]
)

Series取前10个 如何取数据前10位数字_PowerBI_05