跳至正文

Tableau15大详细级别表达式 · DAX复刻与解读(图文视频)

标签:

TOP 15 LOD expressions 案例,是 Tableau 9.0版本推出的LOD 功能经典案例,也可以作为评价 BI 工具优劣的标准之一。

【Tableau】15大详细级别表达式-思路解读版 (3) 2018/11

本文,尝试用详细级别和表逻辑,讲解 DAX 的实现,让读者更加坚信 Tableau 多么的易用!

编号难点更新日期
LOD1-Customer Order frequency
客户频次分析
聚合表的二次聚合;“上下文转换”2024/10/06
LOD2- Cohort Analysis
客户阵列分析
聚合表和底表的世系;“上下文转换”2024/10/07
LOD3- Daily profit KPI
每日的利润贡献及分类汇总
预先聚合的二次判断 2024/10/13

LOD15-4 Percent of total
不同层级的合计百分比
多个层次的预先聚合和计算优先级。2024/10/26

⚠️ 未经授权,请勿将本文用于企业内部的培训、文档等商业活动。请各位国产 BI 同行尊重他人的劳动成果,要么付出你的金钱,要么表达你的尊重!二不相沾,非奸即盗。

LOD1 预先聚合作为维度:“不同订单频次的客户数量”

2024/10/05 调整次序,补充方法2 . 参考 https://dax.do/KSy9ReSx5rPtqm/

方法1:使用 Addcolumns 构建中间表

比如使用AddColumn函数创建一个table,如下:

CUS_ID_rfm = ADDCOLUMNS(
 VALUES('Global Superstore'[Customer ID]),   -- GROUP BY CUS_ID
 "F_order_cnt", CALCULATE(DISTINCTCOUNT('Global Superstore'[Order ID])),  -- FREQUENCE
 "M_sales_sum", CALCULATE(SUM('Global Superstore'[Sales])),                    -- MONTARY
 "1st_order_dt", CALCULATE(MIN('Global Superstore'[Order Date])),    -- FISST ORDER DATE
 "last_order_dt", CALCULATE(MAX('Global Superstore'[Order Date])),       -- LAST 
 "R_last_to-today", DATEDIFF( CALCULATE(MAX('Global Superstore'[Order Date])),TODAY(),MONTH)   -- r 
    ) 

虽然这里没有使用Summarize 等函数,其实 values 可以视为 Summarize 的简化形式之一,因此上述中间表也是一个“聚合中间表”。

这里包含了常见的字段。它会独立于原来的明细表创建一个聚合中间表,甚至可以在关系模型哪里看到。

之后在这种表的基础上,就可以创建分布了。

个人不建议使用“参数表”这样的复杂设置,参数表是“反分析”的,在需要交互的情况下才优先考虑。

方法2:使用 SummarizeColumns 创建聚合中间表

2024/10/05 更新

上面的 addcolumns 相当于构建了一个近乎物化的中间表,如果跳过这个阶段,仅仅在分析中创建临时中间表,可以如下:

 DEFINE table  mid = 
 SUMMARIZECOLUMNS (
    Sales[CustomerKey],
    sales,
    "order_cnt",DISTINCTCOUNT ( Sales[Order Number])
    )
EVALUATE
SUMMARIZECOLUMNS (
     mid[order_cnt],
     mid,
     "f_wrong",CALCULATE (DISTINCTCOUNT (Sales[CustomerKey])),
     "f_R",CALCULATE (DISTINCTCOUNT (mid[CustomerKey]))   -- 可以直接引用 addcolumn 中的字段
     )
     

在上面的代码中,DEFINE 首先定义了一个中间表 mid,其中使用 Summarizecolumns 函数计算了“不同客户的订单数量”。

而后,在 mid 聚合中间表基础上,再次使用 SummarizeColumns 完成二次聚合——以 mid 的聚合值”order_cnt”为最终问题的维度,以此前的CustomerKey 聚合成为度量。 

两个数据表的结果预览

方法3:使用计算列和上下文转换 

创建column(计算列),使用calculate计算订单频次,结合ALLexcept使聚合依据指定到客户ID字段,从而获得tableau中{ FIXED [客户ID]: COUNTD([ORDER ID])} 的效果。

DAX计算如下:

1ST_column_ALLEX = CALCULATE(
            DISTINCTCOUNT('Global Superstore'[Order ID]),
            ALLEXCEPT('Global Superstore','Global Superstore'[Customer ID])
        )

由于它是calculated column,计算在数据源刷新时完成,【计算列】字段可以等价于数据表字段,因此在最终可视化中,既可以作为分类维度,又可以被聚合作为度量。如果使用Measure完成上述计算,结果无法作为维度使用。

在视图中,分类是:客户订单频次,答案是“客户ID不同计数”,没有筛选范围。结果如下所示:

视频讲解与 DAX 代码

视频仅仅保留了 dax 的部分,完整部分查看《DAX 别裁新解》。

完整 CODE: 欢迎访问 https://dax.do/KSy9ReSx5rPtqm/

-- LOD 15-1  1. Customer order frequency
DEFINE
    -- method 1 
    TABLE mid =
        SUMMARIZECOLUMNS (
            Sales[CustomerKey],
            Sales,
            "order_cnt", DISTINCTCOUNT ( Sales[Order Number] )
        )
    -- mothod 2 
    COLUMN Sales[Frequency] =
        CALCULATE (
            DISTINCTCOUNT ( Sales[Order Number] ),
            ALLEXCEPT ( Sales, Sales[CustomerKey] )
        ) --  聚合需要分组依据 ,无分组聚合

-- 客户的订单频次 ,据此定义中间表 mid
EVALUATE
SUMMARIZECOLUMNS (
    Sales[CustomerKey],
    Sales,
    "cnt", DISTINCTCOUNT ( Sales[Order Number] )
)

--method1 : DEFINE table  mid  ,然后二次聚合
EVALUATE
SUMMARIZECOLUMNS (
    mid[order_cnt],
    mid,
    "f_wrong", CALCULATE ( DISTINCTCOUNT ( Sales[CustomerKey] ) ),
    "f_Right", CALCULATE ( DISTINCTCOUNT ( mid[CustomerKey] ) )   -- 可以直接引用 addcolumn 中的字段
)

-- method 2 :跳过中间表,直接定义 聚合的计算列。 columns 每个客户 的 订单频次
-- define COLUMN Sales[Frequency] 从这里而来 
EVALUATE
ADDCOLUMNS (
    Sales,
    "add_frequency",
        CALCULATE (
            DISTINCTCOUNT ( Sales[Order Number] ),
            ALLEXCEPT ( Sales, Sales[CustomerKey] )
        ) --  聚合需要分组依据 ,无分组聚合
)
--method 2 从 column直接完成聚合
EVALUATE
SUMMARIZECOLUMNS (
    Sales[frequency],
    -- group by 
    Sales,
    "customer cnt", DISTINCTCOUNT ( Sales[CustomerKey] )
)


LOD2 预先聚合作为分类:“客户阵列分析 cohort analysis”

这就也需要“计算列”(calculated column)出场,计算列的性质等价于数据表字段,在数据表刷新时先于任意可视化视图而完成计算。典型的计算列字段有行级别的计算列和迭代计算列两种。

这个题目的难点是计算“每个客户的获客日期”,并与之前的数据表构建逻辑上的关系。如果单看获客日期,只需要如下即可:

EVALUATE
 SUMMARIZECOLUMNS (Sales[CustomerKey],
     sales,
     "cohort_year", MINX (Sales, (Sales[Order Date]))
     )

可以先验证一下,如下所示,可以获得每个客户 ID(customerKey)对应的首次订单日期(这里还没有转换年):

先说错误的方法:世系错误导致分组失败

这里介绍一种行不通的方法,即尝试构建一个中间表,而后从底表和中间表分别获得最终需要的维度。

如下所示,构建一个中间表,获得每个客户的首次订单日期:

DEFINE 
TABLE LOD15_2_table = 
  EVALUATE
 SUMMARIZECOLUMNS (Sales[CustomerKey],
     sales,
     "cohort_year", MINX (Sales, year(Sales[Order Date]))
     )

最终的问题中,一个维度来自于上面的 cohort_year,另一个来自于订单日期对应的年度,二者构成聚合的分组依据。因此,看似可行的答案继续如下:

 DEFINE 
  TABLE LOD15_2_table = 
  EVALUATE
 SUMMARIZECOLUMNS (Sales[CustomerKey],
     sales,
     "cohort_year", MINX (Sales, year(Sales[Order Date]))
     )
  EVALUATE
   SUMMARIZECOLUMNS (
     Sales[Order_year],
     LOD15_2_table[cohort_year],
     Sales,
     "total quantity",CALCULATE ( 
                                 SUMX ( Sales,Sales[Quantity]) --  默认仅受到 Sales 表的字段约束
                               )
     )

但是,上面的聚合度量,无法从中间表 cohort_year 字段获得世系(lineage)关系,因此无法成为聚合的依据,获得聚合结果只是第一个分组字段的。 

正确的方法1:创建一个包含所有要素的中间表

难点在于,如何把视图中所需要的所有字段(cohort_year、Order_year 以及聚合需要的 quantity——这里以 quantity 代替销售额,简化操作),都放在一个中间表中。如下所示:

EVALUATE
    ADDCOLUMNS (
        SUMMARIZE(   Sales ,
            Sales[CustomerKey],
            Sales[Order Date] ),
        "total qty",CALCULATE ( sum(Sales[Quantity]) ),
        "cohort year",CALCULATE ( min(Sales[Order Date]) ,
                                ALLEXCEPT (Sales, Sales[CustomerKey]))
    )

这里的关键是最后的 Cohort_year,这里需要使用 allexcpet 确保它仅仅指定客户 ID 计算最小日期。

以此为基础,就可以构建基于中间表的最终查询。

DEFINE 
TABLE   LOD15_2_mid_table = 
    ADDCOLUMNS (
        SUMMARIZE(   Sales,
            -- filter(Sales, AND (Sales[CustomerKey]<= 17421,Sales[CustomerKey]>= 17419 )) , --  验证使用
            Sales[CustomerKey],
            Sales[Order Date]  ),
        "total_qty",    CALCULATE ( SUM (Sales[Quantity] )),
        "cohort_date",  CALCULATE ( MIN (Sales[Order Date]) ,
                                ALLEXCEPT (Sales, Sales[CustomerKey]))
    )

EVALUATE 
    ADDCOLUMNS ( 
       SUMMARIZE (LOD15_2_mid_table,
         LOD15_2_mid_table[cohort_date],
         LOD15_2_mid_table[Order Date] ),
        --LOD15_2_mid_table,
        "qty",CALCULATE (sum(LOD15_2_mid_table[total_qty]))
        )
    

结果如下所示,这里没有对日期转化为年度处理,除了增加一层嵌套,似乎没有好办法。这一点,我对 DAX 表示很不解,为什么那么多地方不能直接使用 Year 函数嵌套日期。

补充一个验证的图片:

基于上述的中间表(包含了最终需要的两个日期字段和一个聚合字段),就可以使用Summarizecolumns 完成最终的聚合了。

正确的方法2:使用逻辑字段和上下文转换

这个方法,相当于把上面临时表的字段逻辑,直接落在底表中,从而跳过了临时表阶段,所以更难以理解。

最终问题的两个年度字段都应该是明细中的 column:订单年度(order_year)、客户阵列年度(cohort_year),前者使用 year 函数计算,后者则需要 Calculate 表达式(包含聚合、指定详细级别,所谓的上下文转换)。

2.1 行级别的计算列:

为了理解方便,使用Year函数创建了 YEAR_ORDER 字段。

DEFINE COLUMN Sales[Order_year]  = Year ( 'Global Superstore'[OrderDate])

2.2 在明细行级别计算每个客户的阵列年度(cohort year)

这里的关键是计算“每个客户的首次订单日期”,而视图中又没有“客户”字段,也就是,分析结果需要每个客户的聚合特征,但是不需要客户本身——这就是大数据分析的关键特征之一。

特别注意,由于后续视图中会出现订单年度,它不能影响这里的MIN计算,因此使用ALL将其从external context中排除;又由于这里的min计算是以客户为依据的,但是这个context在外部不存在,因此通过allexcept将其加入计算的internal context。 这样,最终的计算,就是不受订单日期影响的、每个客户ID的首次订单日期。

(思考:这里是否可以删除 ALL(‘Global Superstore'[YEAR_ORDER]) 条件? 可以。) 

    -- LOD 15-2 method2 
DEFINE    COLUMN Sales[LOD15_2_Cohort_year] =
        CALCULATE (
            MINX ( Sales, YEAR ( Sales[Order Date] ) ),
            ALL ( Sales[Order Date] ),
            ALLEXCEPT ( Sales, Sales[CustomerKey] ) -- fixed customerKey level to aggregate 
        ) 


当然,我从网上找到了另一个人的不同写法,也获得了相同的可视化图形,这里使用了EALIER函数。

First_Order_dt = MINX( 
      FILTER('Global Superstore', 
            'Global Superstore'[Customer ID] = EARLIER('Global Superstore'[Customer ID])
            ),
            'Global Superstore'[Order Date]
    )

(Nov 28, 2022补充)这里的EARLIER函数相当于是Row context的嵌套引用,在《DAX圣经》中,作者推荐使用var变量代替这个语法,从而更好理解嵌套关系和优先级。如下:

VAR cust_ID = 'Global Superstore'[Customer ID]   -- 每个客户ID ,row context
First_Order_dt =MINX(
             FILTER('Global Superstore',
                    'Global Superstore'[Customer ID]= cust_ID
                    ),
           'Global Superstore'[Order Date]
        )

不过,喜乐君认为这种方式都颇为生涩、难于理解。完全可以跳过 Earlier 和 VAR 部分——与其在 MINX 迭代函数中指定计算的范围,不如在 Calculate 表达式中指定计算的详细级别!

2.3 基于上述两个计算列字段,完成最终计算

基于上述的 Order_year 和 Cohort_year 字段,再加上 Sales 表中已有的Quantity(这里替代销售额),就可以直接完成最终的视图聚合了。

DEFINE
    COLUMN Sales[Order_year] =
        YEAR ( Sales[Order Date] )    -- LOD 15-2 method2 
    COLUMN Sales[LOD15_2_Cohort_year] =
        CALCULATE (
            MINX ( Sales, YEAR ( Sales[Order Date] ) ),
            ALL ( Sales[Order Date] ),
            ALLEXCEPT ( Sales, Sales[CustomerKey] ) -- fixed customerKey level to aggregate 
        ) 
EVALUATE
SUMMARIZECOLUMNS (
    Sales[Order_year],
    Sales[LOD15_2_Cohort_year],
    Sales,
    "total quantity", CALCULATE ( SUMX ( Sales, Sales[Quantity] ) --  默认仅受到 Sales 表的字段约束
        )
)

如果使用 SummarizeColumns 表达式,Calculate 这里可以省略的;如果是 AddColumns 结合 Summarize,那么 Calculate 则是必须的。

计算结果如下:

相比于 LOD15-1,这个案例的难点是两个维度字段,都是计算而来,其中一个来自于明细,另一个来自于“预先聚合”,如何确保二者世系关系的一致性是难点。

视频讲解(DAX 部分):

视频讲解对应的 DAX 代码: 参见 https://dax.do/Fcx1S9EMmynQvN/

-- LOD 15-2 
-- cohort year ,order year ,sum (quanlity ) 
-- 不同年度 的销售数量 
DEFINE 
    COLUMN  sales[order_year] = 
        Year(Sales[Order Date])
    TABLE cohort =    -- wrong 
        SUMMARIZECOLUMNS ( Sales[CustomerKey],
        sales,
        "cohort_year", min(Sales[Order Date])
        )
     TABLE  cohort_table = 
         SUMMARIZECOLUMNS ( 
            Sales[Order Date],
            Sales[CustomerKey],
            sales,
            "qty", sum(Sales[Quantity]),
            -- "cohort date-wrong", CALCULATE (  min(Sales[order date]) ) , --     为聚合 强制指定详细级别 分组依据
            "cohort date", CALCULATE (  min(Sales[order date]),
                            ALLEXCEPT (sales, Sales[CustomerKey])
                            )  --     为聚合 强制指定详细级别 分组依据 , 每个客户 的 首次订单日期
               )
     
     COLUMN sales[cohort_year] = 
             CALCULATE (  min(Sales[order_year]),
                    ALLEXCEPT (sales, Sales[CustomerKey])
                    )  --     为聚合 强制指定详细级别 分组依据 , 每个客户 的 首次订单日期
    

  --result 1  , total quanty by order year 
EVALUATE
SUMMARIZECOLUMNS ( 
    Sales[order_year], 
    sales,
    "total qty", sum(Sales[Quantity])
    )
    
--  result 2  : cohort date of each customerKey
EVALUATE
SUMMARIZECOLUMNS ( Sales[CustomerKey],
    sales,
    "cohort date", min(Sales[order_year])
    )
    
--result 3 --wrong  of lienage 
EVALUATE 
    SUMMARIZECOLUMNS (Sales[order_year], 
               cohort[cohort_year],
               sales,
               "total qty",sum(Sales[Quantity])
               )
--result 4               
--right mothod 1  :middle table with all element in questions 
EVALUATE
SUMMARIZECOLUMNS ( 
    Sales[Order Date],
    Sales[CustomerKey],
    sales,
    "qty", sum(Sales[Quantity]),
    -- "cohort date-wrong", CALCULATE (  min(Sales[order date]) ) , --     为聚合 强制指定详细级别 分组依据
    "cohort date", CALCULATE (  min(Sales[order date]),
                    ALLEXCEPT (sales, Sales[CustomerKey])
                    )  --     为聚合 强制指定详细级别 分组依据 , 每个客户 的 首次订单日期
   )
--result 5
  /* var cohort_expand =  
   --Table variable 'cohort_table' cannot be used in current context because a base table is expected.
      ADDCOLUMNS (cohort_table, 
          "order_year",  year(cohort_table[Order Date]),
          "cohort_year", year(cohort_table[Cohort date])
      )
  */
EVALUATE   --  扩展表如何我继续被计算,卡住了 
ADDCOLUMNS (cohort_table,
          "order_year", year(cohort_table[Order Date]),
          "cohort_year", year(cohort_table[Cohort date])
          )
-- summarize based on cohort_table 
EVALUATE
  SUMMARIZECOLUMNS (
      cohort_table[Order Date],
      cohort_table[Cohort date],
      cohort_table,
      "total qty", SUMX (cohort_table,cohort_table[qty])
      )
     
   
        
--mothod  2:    add columns to base table 
EVALUATE
ADDCOLUMNS ( 
      sales,
          "cohort date",
             CALCULATE (  min(Sales[order_year]),
                    ALLEXCEPT (sales, Sales[CustomerKey])
                    )  --     为聚合 强制指定详细级别 分组依据 , 每个客户 的 首次订单日期
        )
        
--result _final - 8 
EVALUATE
SUMMARIZECOLUMNS ( 
    Sales[order_year], 
    sales[cohort_year],
    sales,
    "total qty", sum(Sales[Quantity])
    )
 


LOD15-3 Daily profit KPI

问题分析

How many days each month are highly profitable, profitable, or unprofitable?

标准问题结构:各年月、不同盈利状态(高盈利/盈利/非盈利)的天数?

1)维度*2:年月(计算可得)、不同盈利状态(预先聚合,作为维度)

      度量*1:天数(可以直接聚合)

2)不同盈利状态:需要在指定详细级别聚合基础上判断 

     —— 基于 “每天的利润总和”的判断,即问题需要引用另一个详细级别的聚合计算

        ——只有fixed LOD能完成这个任务(引用其他层次的聚合,返回作为维度)

⚠️ 问题三个部分:分析范围、问题描述(维度)、问题答案(度量)

1、Tableau 的 LOD 方案

可以把 lod 理解为表,也可以理解为元组,甚至字段。

if { FIXED  [Order Date]: SUM([Profit])} >1000 
    then 'highly profitable'
elseif { FIXED  [Order Date]: SUM([Profit])} >0 
    then 'profitable'
else   'unprofitable'
END

2、DAX 方案

理解的关键,在于预先聚合之后的二次判断。之后,基于上面的 columns 继续扩展列:

DEFINE 
COLUMN sales[daily_qty] =  CALCULATE (   --  为聚合指定分组依据 
                            sum( Sales[Quantity]) ,
                            ALLEXCEPT ( sales, Sales[Order Date])   -- fixed order date 
                            )   
COLUMN sales[tag] = if(sales[daily_qty]  > 200 , "high", "low" )

最重要的地方,是理解预先聚合和底表、问题之间的关系。

视频解说(简化版):

对应的代码https://dax.do/SA9nu0P5h2AsAp/

/* LOD 15-3 XILEJUN.com
How many days each month are highly profitable, profitable, or unprofitable?
标准问题结构:各年月、不同盈利状态tag(高盈利/盈利/非盈利)的天数?
1、维度*2:年月(计算可得)、不同盈利状态(预先聚合,作为维度)
      度量*1:天数(可以直接聚合)
2、不同盈利状态:需要在指定详细级别聚合基础上判断 
*/
--  难点 :如何把高阶问题转化为低阶问题? 预先完成聚合  
--  注意:define column  需要指定表名!
-- EVALUATE 
DEFINE TABLE mid = 
SUMMARIZECOLUMNS ( Sales[Order Date],
                  "daily_qty",  sum(Sales[Quantity])
                    )
COLUMN sales[year] = YEAR(Sales[Order Date])
                
COLUMN sales[month] = MONTH(Sales[Order Date])

COLUMN sales[daily_qty] =  CALCULATE (   --  为聚合指定分组依据 
                            sum( Sales[Quantity]) ,
                            ALLEXCEPT ( sales, Sales[Order Date])   -- fixed order date 
                            )              
COLUMN sales[tag] = if(sales[daily_qty]  > 200 , "high", "low" )


EVALUATE 
-- TABLE mid_expand = 
ADDCOLUMNS (mid,
        "tag", if(mid[daily_qty] >100 , "high","low" )
        )
EVALUATE 
    sales
EVALUATE 
SUMMARIZECOLUMNS ( sales[year],sales[month], sales[tag],
            sales,
            "daily_cnt" , DISTINCTCOUNT ( Sales[Order Date])
            )

3、SQL 方案

更好地理解表关系(但又不同);关系不是连接。

-- LOD 15-3 
 -- How many days each month are highly profitable, profitable, or unprofitable?
 -- 标准问题结构:各年月、不同盈利状态(高盈利/盈利/非盈利)的天数?

SELECT 
    date_part('year', a."Order Date")  AS YE ,
    date_part('month', a."Order Date") AS MON ,
    b.tag AS tag,                                       -- tag = daily profit + if 
    count(DISTINCT  a."Order Date")
FROM public.superstore_en a
INNER JOIN 
    (
    SELECT  
    "Order Date", 
     sum("Profit") AS pr,
    CASE WHEN  SUM("Profit") > 500 THEN 'high' ELSE 'low' END AS tag 
    FROM public.superstore_en   c
    GROUP BY 1 
    ) b ON a."Order Date" = b."Order Date"
 GROUP BY 1,2 ,3 

LOD5-4 Percent of total

问题描述:

For a given market (region), what is each country‘s percent of total global sales?
标准问题结构:在选定市场中,每个国家的销售额、在全球销售的占比?

这个题目的关键是:识别问题中存在的四个详细级别,以及它们对应计算的优先级。

四个详细级别分别是:

  • L1:最高聚合度对应的详细级别,是 Percent of total 的 total,或者说百分比的“分母”部分。
  • L2:Market 详细级别,仅次于最高聚合度,是筛选条件对应的级别。
  • L3:Country 详细级别,是问题详细级别对应的级别,或者说主视图。
  • Lx:数据表记录对应的详细级别,是所有聚合最终的起点。

优先级 的关键是:total应该在筛选之前。

4.1 Tableau 的 FIXED LOD 方案

在 Tableau 中,只有 fixed LOD 的结果在“market= EU”这样的行级别筛选器之前,指定最高聚合度对应的详细级别,可以直接用如下的表达式:

{fixed :SUM (quantity)} 或者 { sum (quantity) }

4.2 DAX 的方案

code:https://dax.do/cuvj0u2Rb70mCC/

4.2.1 DAX 方案之 Measure

如果一个 measure 想要在筛选器之前完成,需要借助于 ALL 调节符。

EVALUATE
SUMMARIZECOLUMNS ( 
        'Product'[Category],
        Sales[ProductKey],
        filter(Sales, Year(Sales[Order Date])=2007 ),
        "qyt", sum(Sales[Quantity]),
        "total qty",  CALCULATE ( sum(Sales[Quantity]),
                                ALL(Sales)),
         "percent of total" , sum(Sales[Quantity])/ CALCULATE ( sum(Sales[Quantity]),
                                ALL(Sales))                          
)

4.2.2 DAX 的方案之 columns

另一个方案,是使用计算列,计算列本身的计算优先级在Summarize 的 filter 之前。

DEFINE COLUMN 
    Sales[L1_qty] = sum(Sales[Quantity])  -- 优先级更高  
    
EVALUATE
SUMMARIZECOLUMNS ( 
        'Product'[Category],
        Sales[ProductKey],
        Sales[L1_qty],    -- columns , dimension 维度  , total before filter 
        filter(Sales, Year(Sales[Order Date])=2007 ),
        "qyt", sum(Sales[Quantity]),
        "percent " ,sum(Sales[Quantity])/ sum(Sales[L1_qty] )
                          
)

4.3 SQL 逻辑

使用子查询获得筛选之前(where 之前)的聚合。聚合的值可以在最终的查询中作为分类,也可以作为度量——看如何被引用。这一点类似于 DAX 的 column和 measure。

下面,这里子查询的结果在最终被视为分类(dimension)。


SELECT 
a."Region",  
a."City", 
b.L1_qty ,   --- DAX ,COLUMNS 
sum(a."Quantity") ,

sum (sum(a."Quantity")  )   OVER ()   
FROM public.superstore_en a 
  , (SELECT 
    sum("Quantity") AS L1_qty FROM  public.superstore_en
    )   b 
WHERE a."Region" = 'West'
GROUP BY 1,2,3

而在下面,我们使用avg 聚合避免重复,只需要 group 1和2即可。


SELECT 
a."Region",  
a."City", 
sum(a."Quantity") ,
sum (sum(a."Quantity")  )   OVER ()  , -- total AFTER FILTER 
avg(b.L1_qty ),   --- DAX ,COLUMNS 
sum(a."Quantity")/avg(b.L1_qty ) AS PERCENT 
FROM public.superstore_en a 
  , (SELECT 
    sum("Quantity") AS L1_qty FROM  public.superstore_en
    )   b 
WHERE a."Region" = 'West'
GROUP BY 1,2

要注意,这里的 over 窗口函数只能完成 where 之后的合计,所以没有使用这个方案。

视频省略,参考 B 站课堂。

《Tableau15大详细级别表达式 · DAX复刻与解读(图文视频)》有1个想法

  1. Pingback: 如何选择BI工具:Power BI“向左”,Tableau“向右”-Tableau喜乐君-敏捷BI布道师

评论已关闭。