4.6 在筛选上下文中使用DISTINCT和SUMMARIZE

在筛选上下文中使用DISTINCT和SUMMARIZE

既然您对评估上下文有深入的了解,我们就可以使用这些知识逐步解决实际问题。同时,我们提供了一些细节的分析,希望能对行上下文和筛选上下文的基本概念有更多的了解。此外,在此示例中,我们还进一步阐述了SUMMARIZE函数,在第3章“使用基本表函数”中作了简要介绍。

在进入更多细节之前,请注意,基于培训的目的,此示例在得出正确的解决方案之前显示了一些不准确的计算。因为我们想教导编写DAX代码的过程,而不是给出解决方案。在制定度量值的过程中,您可能会犯几个初始错误。在此指导示例中,我们描述了正确的推理方法,可帮助您自己解决类似的错误。

要求是计算Contoso客户的平均年龄。即使这看起来是合理的要求,也并不完整。我们是在谈论他们的当前年龄还是在购买时的年龄?如果客户购买了3次,那么平均应算作一次事件还是三次事件?如果他们在不同年龄段购买了三次,该怎么办?我们需要更加精确。这是更完整的要求:“计算产生销售时客户的平均年龄,如果每个客户在同一年龄进行多次购买,则仅计算一次。”

该解决方案可以分为两个步骤:

  • 计算购买发生时的客户年龄
  • 平均化

每次销售时客户的年龄都会改变。因此,年龄需要存储在Sales表中。对于Sales中的每一行,可以计算产生销售时的客户年龄。计算列非常适合此需求:

Sales[Customer Age] =
DATEDIFF (                            -- Compute the difference between
    RELATED ( Customer[Birth Date] ), -- the customer's birth date
    Sales[Order Date],                -- and the date of the sale
    YEAR                              -- in years
)

由于Customer Age是计算列,因此将在迭代Sales的行上下文中对其进行评估。该公式需要访问与客户关系一侧的Customer[Birth Date](客户生日),这是Customer(客户)表中的一列。在这种情况下,需要RELATED才能让DAX访问目标表。在示例数据库Contoso中,许多客户的生日为空。如果第一个参数为空,则DATEDIFF返回值为空。

因为要求提供平均值,所以第一个且不准确的解决方案可能是对该列求平均值的度量值:

Avg Customer Age Wrong := AVERAGE ( Sales[Customer Age] )

结果不正确,因为如果客户在某个年龄进行多次购买,则 Sales [Customer Age] 将包含多个具有相同年龄的行。要求仅计算每个客户一次,此公式未遵循这样的要求。图4-25并排显示了最后一个度量值的结果和预期结果。

图4-25 一个简单的平均值计算得出的客户年龄的错误结果

这是问题所在:每个客户的年龄只能计算一次。一个可能的解决方案(仍然不准确)将是通过以下措施对客户年龄进行平均,然后取平均值:

Avg Customer Age Wrong Distinct :=
AVERAGEX (                             -- Iterate on the distinct values of
    DISTINCT ( Sales[Customer Age] ),  -- Sales[Customer Age] and compute the
    Sales[Customer Age]                -- average of the customer's age
)

此解决方案不是正确的解决方案。实际上,DISTINCT 返回客户年龄的不同值。此公式仅计算一次两个具有相同年龄的客户。要求是对每个客户计数一次,而此公式对每个年龄计数一次。实际上,图4-26显示了具有“平均客户年龄”新公式的报告。您会看到此解决方案仍然不准确。

图4-26 不同客户年龄的平均值仍然是错误的

在最后一个公式中,可能尝试用CustomerKey作为DISTINCT的参数替换Customer Age,如以下代码所示:

Avg Customer Age Invalid Syntax :=
AVERAGEX (                             -- Iterate on the distinct values of
    DISTINCT ( Sales[CustomerKey] ),   -- Sales[CustomerKey] and compute the
    Sales[Customer Age]                -- average of the customer's age
)

此代码包含错误,DAX不会接受。您可以在不阅读下一段中提供的解决方案的情况下找出原因吗?

AVERAGEX生成对表进行迭代的行上下文。作为AVERAGEX的第一个参数提供的表是DISTINCT(Sales [CustomerKey])。DISTINCT返回仅包含一列的表以及客户键的所有唯一值。因此,由AVERAGEX生成的行上下文仅包含一列,即Sales [CustomerKey]。DAX无法在仅包含Sales [CustomerKey]的行上下文中评估Sales [客户年龄]

所需要的是行上下文,其粒度为Sales [CustomerKey],但还包含Sales [Customer Age]。第3章介绍的SUMMARIZE可以生成两列的现有唯一组合。现在,我们终于可以显示实现所有要求的此代码的版本:

Correct Average :=
AVERAGEX (                     -- Iterate on
    SUMMARIZE (                -- all the existing combinations
        Sales,                 -- that exist in Sales
        Sales[CustomerKey],    -- of the customer key and
        Sales[Customer Age]    -- the customer age
    ),                         --
    Sales[Customer Age]        -- and average the customer's age
)

像往常一样,可以使用变量将计算分为多个步骤。请注意,访问Customer Age列仍需要在AVERAGEX函数的第二个参数中引用Sales表名称。变量可以包含表,但不能用作表引用。

Correct Average :=
VAR CustomersAge =
    SUMMARIZE (                -- Existing combinations
        Sales,                 -- that exist in Sales
        Sales[CustomerKey],    -- of the customer key and
        Sales[Customer Age]    -- the customer age
    )
RETURN
AVERAGEX (                     -- Iterate on list of
    CustomersAge,              -- Customers/age in Sales
    Sales[Customer Age]        -- and average the customer's age
)

SUMMARIZE生成当前筛选上下文中可用的客户和年龄的所有组合。因此,具有相同年龄的多个客户将复制该年龄,每个客户一次。AVERAGEX忽略表中存在CustomerKey的情况;它仅使用客户年龄。CustomerKey*只需用来计算每个年龄段的正确出现次数。

值得强调的是,完整的度量值在报表生成的筛选上下文中执行。因此,SUMMARIZE只会评估和返回购买商品的客户。报告的每个单元格都有不同的筛选上下文,度量值仅考虑购买了至少一种对应报告中显示颜色产品的客户。

结论

现在该回顾一下您在本章中学到的有关评估上下文的最相关主题。

  • 有两个评估上下文:筛选上下文和行上下文。这两个评估上下文不是同一概念的变体:筛选上下文过滤模型;行上下文迭代一个表。
  • 要了解公式的行为,您总是需要考虑两个评估上下文,因为它们同时运行。
  • DAX为计算列自动创建行上下文。也可以使用迭代函数以编程方式创建行上下文。每个迭代函数都定义一个行上下文。
  • 您可以嵌套行上下文,如果它们位于同一表上,则最里面的行上下文将隐藏同一表上的先前行上下文。当访问所需的行上下文时,变量可用于存储检索到的值。在DAX的早期版本中,变量不可用,而EARLIER函数用于访问前一行上下文。从今天起,不鼓励使用EARLIER。
  • 当遍历表表达式返回的表时,行上下文仅包含表表达式返回的列。
  • 当您在行、列、切片器和筛选上使用字段时,Power BI等客户端工具会创建筛选上下文。也可以使用CALCULATE以编程方式创建筛选上下文,我们将在下一章中介绍它。
  • 行上下文不会自动通过关系传播。需要使用RELATEDRELATEDTABLE强制传播。您需要在一对多关系正确一侧的行上下文中使用这些函数:在“多”侧使用RELATED,在“一”侧使用RELATEDTABLE。
  • 筛选上下文过滤模型,并根据其交叉筛选方向使用关系。它总是从一侧传播到另一侧。此外,如果您使用双向交叉筛选方向,则传播也会从多侧向一侧发生。

至此,您已经学习了DAX语言最复杂的概念主题。这些要点支配您公式的所有评估流程,它们是DAX语言的支柱。每当遇到无法计算所需内容的表达式时,很有可能是因为您没有完全理解这些规则。

正如我们在导言中所说,乍一看,所有这些主题看起来都很简单。实际上也简单。使它们变得复杂的原因是,在DAX表达式中,您可能在公式的不同部分具有多个评估上下文。掌握评估上下文是您要通过经验获得的技能,我们将在下一章中通过显示许多示例来帮助您。编写了自己的一些DAX公式后,您将直观地知道使用了哪些上下文以及它们需要哪些函数,最终您将掌握DAX语言。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354

推荐阅读更多精彩内容

  • 第4章了解评估上下文 4.1 介绍评估上下文 到此,您已经学习了DAX语言的基础知识。您知道如何创建计算列和度量值...
    jweishan阅读 939评论 0 1
  • 在迭代函数中使用行上下文 您了解到,无论何时定义计算列或使用X函数开始迭代时,DAX都会创建行上下文。当我们使用计...
    jweishan阅读 1,399评论 0 2
  • 到本书的这一章时,您已经学习了DAX语言的基础知识。您知道如何创建计算列和度量值,并且您已经很好地理解了DAX中的...
    daxbi阅读 6,624评论 4 28
  • 处理多个表 既然您已经了解了评估上下文的基础知识,我们就可以描述上下文在关系方面的行为。实际上,很少有数据模型仅包...
    jweishan阅读 788评论 1 2
  • 近来的天气很可怕,好好的母亲节是想陪妈妈和家人好好过的,无奈总有些事不会放过你,心情一直处于快要爆炸的状态,啊啊啊...
    朴白白阅读 245评论 0 0