9

DA.PBI-DAX指南(上)

 2 years ago
source link: https://segmentfault.com/a/1190000040257816
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

上篇: Power BI 概览笔记

DAX基本语法

  • 引用表中的列(如果不是数字开头,不包含空格,也不是保留字,可省略单引号)例:

    'Sales'[Quantity]

最佳实践:在列引用中始终使用表名,在度量值引用中始终避免使用表名。以此在阅读代码时区分度量值和列。

  • 注释:单行注释(//--
  • 数据类型:Integer,Decimal,Currency,DateTime(闰年错误,需要≥1900-03-01),Boolean,String,Variant,Binary
  • 运算符 (),+-*/,比较运算符,&&,||,IN,NOT
  • 运算符重载,强制转换

    • 时间,例: Sales[OrderDatePlusOneWeek] = Sales[Order Date] + 7
    • 文本链接,例:= 5 & 4返回"54"
    • 运算符,例:= "5" + "4"返回9。
  • 表构造器:单列{"Red","Blue","White"},多列{(1,2,3),}
  • 条件语句: IF(exp,true,false)
  • 计算列和度量值

    • 计算列:在内存数据库刷新时进行逐行运算,占用空间减慢运行速度。一般用来开发时观察中间值。
    • 度量值:对多行聚合计算。(在视觉对象筛选上下文或DAX查询上下文计算)

      以下操作必须定义计算列

      • 将计算结果置于切片器中,透视表或矩阵的行区域、列区域(而并不是值区域),或使用计算列作为DAX查询的筛选条件
      • 定义严格绑定到当前行的表达式(例:价格×数量)
      • 对文本或数值做分类时(例:客户的年龄范围:0~18,18~25)

      在筛选报表查看结果时定义度量值

      • 基于报表的筛选条件计算利润率
      • 有变分和地区筛选器的情况计算一个产品销售额占所有产品销售额的比例
  • 变量VAR ... RETURN ...避免重复写表达式,提高可读性和性能

    • 变量范围的规则(块级作用域):

      • 一个变量在其所在的VAR/RETURN代码块的RETURN部分可用,并且在VAR/RETURN代码块中,在这个变量之后定义的所有变量也可以使用它。VAR/RETURN代码块可以替换任何DAX表达式,在这些表达式中可以读取变量。
      • 变量在定义其自身的VAR/RETURN代码块之外不可用。
  • 错误处理(转换错误,计算错误,空值缺失值)

      • IFERROR(Sales[Quantity] * Sales[Price], BLANK())
      • ISERRORISBLANK
    • 抛出错误ERROR()
    • 格式化 DAXFormatter.com
  • 聚合函数和迭代函数

    • 聚合函数:在列上计算。一般对数值或日期,MIN/MAX可对文本。(SUM,AVERAGE,MIN,MAX,STDEV)

      Sales[DaysToDeliver] = INT( Sales[Delivery Date] - Sales[Order Date])
      AvgDelivery:=AVERAGE(Sales[DaysToDeliver])
    • 迭代函数:聚合表达式。(SUMX,MINX,FILTER,ADDCOLUMNS,GENERATE)

      • 一般至少包括2个参数。1.扫描的表,2.为表的每一行计值得表达式。

        AvgDelivery:=AVERAGEX(
        Sales , 
        INT( Sales[Delivery Date] - Sales[Order Date])
        )
  • 表函数(FILTER,ALL,ALLEXCEPT

    • 迭代表,例:

      Sales Amount Multiple Items :=SUMX(
       FILTER(Sales,Sales[Quantity]>1),
       Sales[Quantity] * Sales[Net Price]
      )
      [DEFINE {MEASURE <tableName>[<name>] = <expression>}]
      EVALUATE <table>
      [ORDER BY {<expression>} [{ASC|DESC}]} [, ...]]
      • ALL 所有行,忽略任何筛选器。支持多列
      • VALUES 所有行,会考虑现有筛选器,空行有效,支持单列
      • DISTINCT 返回不同值,会考虑现有筛选器,不返回空行,支持单列
      • ALLNOBLANKROW 支持多列

      将表用作标量值:具有单行和单列的表key像标量值一样使用

      Brand Name:= IF(
       COUNTROWS (VALUES(Product[Brand]))=1,
       VALUES(Product[Brand])
      )
      ---
      Brand Name:= IF(
       HASONEVALUE (Product[Brand]),
       VALUES(Product[Brand])
      )
      Brand Name:= SELECTEDVALUE (Product[Brand], "Mutiple brands" )

      ALLSELECTED 在当前报表中可见且只考虑当前视觉对象之外的所有筛选器

      Sales Pct :=DIVIDE(
       SUMX( Sales , Sales[Quantity] * Sales[Net Price] ),
       SUMX( ALL(Sales) , Sales[Quantity] * Sales[Net Price] )
      )
      ---
      Sales Pct :=DVIDE(
       SUMX( Sales , Sales[Quantity] * Sales[Net Price] ),
       SUMX( ALLSELECTED(Sales) , Sales[Quantity] * Sales[Net Price] )
      )

      计值上下文

    • 筛选上下文: 筛选模型
    • 行上下文: 迭代表
    • 嵌套多个表的行上下文

      SUMX(
       'Product Category',
       SUMX(
       RELATEDTABLE('Product'),
       SUMX(
         RELATEDTABLE(Sales),
         Sales[Quantity] * Product[Unit Price] * 'Product Category'[discount]
       )
       )
      )
      ---
      SUMX(
       Sales,
       Sales[Quantity] * RELATED(Product[Unit Price]) * RELATED('Product Category'[Discount])
      )
    • 同一个表上的多层嵌套行上下文

      Product[UnitPriceRankDense] = 
       VAR PriceOfCurrentProduct = Product[Unit Price]
       VAR HigherPrices = 
       FILTER (
         VALUES(Product[Unit Price]),
         Product[Unit Price] > PriceOfCurrentProduct
       )
       RETURN COUNTROWS(HigherPrices) + 1
      ---
       Product[UnitPriceRankDense] = COUNTROWS(
       FILTER(
         VALUES(Product[Unit Price]),
         Product[UnitPrice] > EARLIER(Product[Unit Price])
       )
       )
      • 需要用多个RELATED函数才能访问关系“一”端的多个表

        Sales[UnitPriceVariance]=Sales[Unit Price] - RELATED(Product[Unit Price])
      • 当迭代发生在关系的“一”端时,使用RELATEDTABLE,它返回对应“多”端的所有行

        Product[NumberOfSales]=COUNTROWS(RELATEDTABLE(Sales ))

CALCULATE 函数

Contoso GM :=
VAR ContosoSales=
    FILTER (
      Sales,
      RELATED(Product[Brand]) = "Contoso"
    )
VAR ContosoMargin =
  SUMX (
    ContosoSales,
    Sales[Quantity] * ( Sales[Net Price] - Sales[Unit Cost] )
  )
VAR ContosoSalesAmount =
  SUMX(
    ContosoSales,
    Sales[Quantity] * Sales[Net Price]
  )
RETURN DIVIDE (ContosoMargin,ContosoSalesAmount)

用CALCULATE实现

Gross Margin: = SUMX ( Sales, Sales[Quantity] * ( Sales[Net Price] - Sales[Unit Cost] ))
Sales Amount: = SUMX ( Sales, Sales[Quantity] * Sales[Net Price] )
GM %: = DIVIDE ( [Gross Margin], [Sales Amount] )

Contoso GM   :=CALCULATE([Gross Margin],Product[Brand]="Contoso")
Contoso GM % :=CALCULATE([GM %],Product[Brand]="Contoso")
  • CALCULATE接受2种类型的筛选器

    • 表形式的值列表
    • 布尔条件,如:

      Sales Amount Red Products :=
      CALCULATE(
        [Sales Amount],
        Product[Color]="Red"
      )
dax会转化为值列表的形式。如:

```dax
[Sales Amount Red Products] :=
CALCULATE (
  SUM(Sales[SalesAmount]),
  FILTER(
    ALL(Product[Color]),
    Product[Color]="Red"
  )
)
```
  • CALCULATE规则总结

      • CALCULATE在计值上下文中执行。该上下文包含一个筛选上下文,可能包含 一个|多个 行上下文。这是公式计值的初始环境
      • CALCULATE创建一个新的筛选上下文,并在其中计值第一个参数。新的筛选上下文只包含筛选上下文。由于上下文转换的作用,所有行上下文在筛选上下文中都消失了。
      • CALCULATE接受三种类型的参数:

        • 在新的筛选上下文中计值的表达式。(总是做为第一个参数)
        • 操作原始筛选上下文的一组显示筛选器参数。每个筛选器参数都可能使用调节器(Modiier),比如 KEEPFILTERS
        • CALCULATE调节器,通过删除一些筛选器或者更改关系结构,可以修改模型、调整原始筛选上下文的范围。
      • 当原始上下文包含 一个|多个 行上下文时,CALCULATE执行上下文转换,添加不可见的隐式筛选器。如果提供行上下文的是使用KEEPFILTERS的表表达式,那么隐式筛选器的行为也会被KEEPFILTERS修改。
      1. CALCULATE在初始值上下文环境中计算所有的显式筛选器参数,包括原始行上下文(如果有的话)和原始筛选上下文。所有的显式筛选器参数在这个初始计值上下文环境中独立计算,计算完成后,CALCULATE开始构建新的筛选上下文。
      2. CALCULATE复制原始筛选上下文,以准备新的筛选上下文。在这个过程中会丢弃原始行上下文,因为新的计值上下文将不包含任何行上下文。
      3. CALCULATE执行上下文转换。它使用列在原始行上下文中的当前值,为正在迭代的所有列提供一个具有唯一值得筛选器。值得注意的是,此筛选器可能包含也可能不包含单个行,因为上下文转换并不保证新的筛选上下文只包含一行。如果没有活动的行上下文,则跳过此步骤。一旦通过上下文转换创建的所有隐式筛选器都位于新的筛选上下文,CALCULATE就会进入步骤4
      4. CALCULATE计算调节器参数USERELATIONSHIP、CROSSFILTER和ALL*(ALL类函数)。这一步发生在步骤3之后。这非常重要,意味着我们可以通过使用ALL来消除上下文转换的影响。
      5. CALCULATE在初始计值上下文环境中计值所有的显式筛选器参数,并将其结果应用于步骤4之后生成的新的筛选上下文。一旦发生了上下文转换,这些筛选器参数就会被应用到新的筛选上下文中覆盖转换生成的上下文。这个过程发生在步骤4之后,也就是ALL*调节器移除上下文和模型关系结构更新之后,所以这一步生成的上下文不会被ALL*所影响。同事,筛选器参数的计算发生在原始上下文中,不受同一个CALCULATE函数中任何其他调节器或筛选器的影响。
      6. 最终,CALCULATE在步骤5生成的筛选上下文中计值第一个参数。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK