隐藏

在Power BI中对数据进行排序(DAX RANKX函数篇)

发布:2024/11/13 9:49:33作者:管理员 来源:本站 浏览次数:302

在Power BI中如果想对数据排序,可以使用DAX中的RANKX函数,格式如下:


RANKX(<table>, <expression>[, <value>[, <order>[, <ties>]]])  


    


主要参数:


   <table>:定义需要进行排序的表单,可以是导入的原始表单,也可以是由DAX函数计算后生成的表单。


   <expression>:定义排序依据的表达式,该表达式必须能返回单一标量结果并且表达式中的参数列需要来自之前定义的table中;之后RANKX函数会根据这个表达式的计算结果进行排序


   RANKX函数的定义看起来很简单,但是使用时有很多注意事项,稍有不慎容易出错。例如以下面这个产品销售表为例,用RANKX函数按销售量对产品进行排序。

   这里写图片描述


先用最简单的思路套用公式,创建一个Measure进行排序,公式如下:


SalesRank = RANKX(Sales,SUM(Sales[Sales]),,DESC)


    


然而,用这个SalesRank结果在Report页面得到的排序表单却有问题, 所有产品的序号都等于1,明显排序结果有误。


这里写图片描述

出现该问题的原因有两点:首先,由于使用了Measure,其特点是会根据创建表单所使用的列动态获取计算结果。Measure的计算结果会受到筛选上下文影响。由于没有使用ALL函数,导致RANKX函数中使用的参数表单Sales,会根据筛选条件Product和SUM[Sales]的变化而变化,相当于每一行数据都在跟自己做排序,因此结果有误。


其次,由于RANKX中的Expression部分没有使用CALCULATE函数将行上下文转换成筛选上下文,导致SUM(Sales[Sales])的计算不受筛选条件影响,变成了对整个Sales列中的数据汇总,从而使得RANKX排序的依据结果都相同,所有Rank No都是1。


要解决以上两个问题可以创建一个Measure计算SUM(Sales[Sales]),之后再使用ALL函数清空其他筛选条件对排序表单的影响,公式改写为:


TotalSales = SUM(Sales[Sales])

SalesRank = RANKX(ALL(Sales[Product]),[TotalSales],,DESC)


  


如果增加一个Country列参与排序,SalesRank公式仍然可以对Product数据进行正确排序,但是对Country列的排序并不正确。之所以有这样的结果原因是当前SalesRank公式只对以Product列为基准的TotalSales进行了排序,Country的TotalSales并没有参与计算,因此在降序排列条件下SalesRank值被统一赋值成最大排序号1。


这里写图片描述


要解决该问题,需要在排序时进行分类,然后对Product列下数据和Country列下数据分别进行排序。


对于分类,可以创建一个Measure使用方法如下:


ISCountry =

COUNTROWS ( Sales )

   = CALCULATE ( COUNTROWS ( Sales ), ALL ( Sales ), VALUES ( Sales[Country] ) )




为了便于说明临时将上一个公式拆解成两个measure

第一部分COUNTROWS ( Sales )的计算结果受到measure所在的筛选上下文条件影响。如果是以Country列作为筛选条件,可以计算出每个Country列下对应值的行数,例如Australia有5行,USA有4行。如果以Product作为筛选条件,可以计算出每个Product列下值对应的行数,例如Accessories有5行,Computers有2两行。如果由Country列+Product列共同作为筛选条件,则每个国家每种产品对应的行数都=1。


第二部分CALCULATE ( COUNTROWS ( Sales ), ALL ( Sales ), VALUES ( Sales[Country] ) ),通过CALCULATE以及ALL和VALUES函数将COUNTROWS ( Sales )限定为只依据Country列作为筛选条件。在这一前提下,即使measure所在的筛选条件是Country列+Product列,该公式也只会按照筛选条件为Country列做输出结果。因此可以判断,当第一部分结果和第二部分结果相同时,当前行对应的数据是Country。


这里写图片描述


有了这个ISCountry列之后就可以用其判断当前行数据的类型,之后分别针对该数据类型进行排序即可获得想要的排序结果。使用公式如下:


NewRank =

IF (

   [ISCountry],

   RANKX ( ALL ( Sales[Country] ), [TotalSales],, DESC ),

   RANKX ( ALL ( Sales[Product] ), [TotalSales],, DESC )

)


这里面,如果当前行数据是Country,则使用ALL函数基于Country列生成一个子表单进行排序。如果前行数据是Product则使用ALL函数基于Product列生成一个子表单进行排序。