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 站课堂。
Pingback: 如何选择BI工具:Power BI“向左”,Tableau“向右”-Tableau喜乐君-敏捷BI布道师
评论已关闭。