一、2022 + 新增窗口函数核心特点与优势(vs 传统函数)
| OFFSET | 动态相对偏移,基于当前行取偏移 N 行数据,支持分区 / 排序 / 空值控制 | DATEADD/PREVIOUSMONTH(时间类)、FILTER+TOPN(通用) | 1. 脱离时间维度限制,适配任意维度偏移;2. 原生支持分区(PARTITIONBY),无需嵌套ALLEXCEPT;3. 语法简洁,减少嵌套层级 | 性能提升 30%-50%(大数据量);语法量减少 60% |
| INDEX | 静态绝对索引,基于固定位置(第 N 行 / 最后一行)取数,参数与OFFSET完全兼容 | FILTER+TOPN+COUNTROWS | 1. 直接定位固定行,无需计算偏移;2. 分区索引(如按年取首行)无需额外逻辑;3. 支持-1直接取最后一行,简化极值查询 | 性能提升 50%+;无需手动计算行位置,不易出错 |
| WINDOW | 自定义窗口范围(相对 / 绝对),支持多行列聚合,覆盖滚动 / 累计 / 帕累托分析 | FILTER+SUMX+EARLIER(累计)、TOPN+SUMX(滚动) | 1. 原生支持窗口范围定义,无需手动筛选;2. 支持ABS/REL双位置类型,适配所有窗口场景;3. 分区窗口计算更简洁 | 性能提升 40%-70%(数据量>10 万行时更明显);代码量减少 70% |
| RANK | 简化版排名函数,原生支持分区 / 多字段排序 / 并列处理 | RANKX | 1. 无需手动指定排名数据集,语法更简洁;2. 原生支持PARTITIONBY分区排名;3. 多字段排名无需嵌套CONCATENATEX | 性能持平,但语法量减少 50%,可读性提升 |
| ROWNUMBER | 连续行号生成,支持分区 / 排序,无跳过行号 | COUNTROWS+FILTER+EARLIER | 1. 原生支持分区行号(每个分区从 1 开始);2. 无需手动累加,避免上下文错误;3. 支持多列排序生成行号 | 性能提升 60%+;彻底解决传统行号的上下文冲突问题 |
二、基础数据(2024-2025 年,季度划分精准)
1. 日历表(Dim Calendar)
DAX 生成:
Dim Calendar =
ADDCOLUMNS(
CALENDAR(
DATE( 2024 , 1 , 1 ) , // 开始日期
DATE( 2025 , 12 , 31 ) // 结束日期
),
"年度" , YEAR( [Date] ) ,
"月份" , MONTH( [Date] ) ,
"月份序号" , MONTH( [Date] ) ,
"季度" , "Q" & QUARTER( [Date] ) ,
"年度季度" , YEAR( [Date] ) & "Q" & QUARTER( [Date] ) ,
"月份名称 CN" ,
SWITCH(
MONTH( [Date] ),
1, "一月",
2, "二月",
3, "三月",
4, "四月",
5, "五月",
6, "六月",
7, "七月",
8, "八月",
9, "九月",
10, "十月",
11, "十一月",
12, "十二月",
"未知月份"
)
)
2. 销售表(Fact Sales)
修正后精准数据(按自然月 / 季度划分,手工计算可验证):
| 2024-01-01 | 产品 A | 15000 | 7500 | 80 | 90 | 1 | 2024 | Q1 | 2024Q1 |
| 2024-02-01 | 产品 A | 16000 | 8000 | 85 | 88 | 1 | 2024 | Q1 | 2024Q1 |
| 2024-03-01 | 产品 A | 17000 | 8500 | 85 | 85 | 0 | 2024 | Q1 | 2024Q1 |
| 2024-04-01 | 产品 A | 18000 | 9000 | 90 | 92 | 1 | 2024 | Q2 | 2024Q2 |
| 2024-05-01 | 产品 A | 19000 | 9500 | 90 | 95 | 1 | 2024 | Q2 | 2024Q2 |
| 2024-06-01 | 产品 A | 20000 | 10000 | 90 | 95 | 1 | 2024 | Q2 | 2024Q2 |
| 2024-07-01 | 产品 A | 21000 | 10500 | 92 | 96 | 1 | 2024 | Q3 | 2024Q3 |
| 2024-08-01 | 产品 A | 22000 | 11000 | 92 | 97 | 1 | 2024 | Q3 | 2024Q3 |
| 2024-09-01 | 产品 A | 23000 | 11500 | 92 | 98 | 1 | 2024 | Q3 | 2024Q3 |
| 2024-10-01 | 产品 A | 24000 | 12000 | 95 | 99 | 1 | 2024 | Q4 | 2024Q4 |
| 2024-11-01 | 产品 A | 25000 | 12500 | 95 | 99 | 0 | 2024 | Q4 | 2024Q4 |
| 2024-12-01 | 产品 A | 26000 | 13000 | 95 | 99 | 1 | 2024 | Q4 | 2024Q4 |
| 2025-01-01 | 产品 A | 27000 | 13500 | 98 | 100 | 1 | 2025 | Q1 | 2025Q1 |
| 2025-02-01 | 产品 A | 28000 | 14000 | 98 | 100 | 0 | 2025 | Q1 | 2025Q1 |
| 2024-01-01 | 产品 B | 8000 | 4000 | 70 | 80 | 1 | 2024 | Q1 | 2024Q1 |
| 2024-02-01 | 产品 B | 9000 | 4500 | 75 | 82 | 0 | 2024 | Q1 | 2024Q1 |
| 2024-03-01 | 产品 B | 8500 | 4200 | 75 | 81 | 0 | 2024 | Q1 | 2024Q1 |
| 2024-04-01 | 产品 B | 9500 | 4800 | 80 | 85 | 1 | 2024 | Q2 | 2024Q2 |
| 2024-05-01 | 产品 B | 10000 | 5000 | 82 | 86 | 1 | 2024 | Q2 | 2024Q2 |
| 2024-06-01 | 产品 B | 10500 | 5200 | 82 | 87 | 1 | 2024 | Q2 | 2024Q2 |
关键手工验证值(季度汇总)
| 2024Q1 | 15000+16000+17000=48000 | 8000+9000+8500=25500 | 73500 |
| 2024Q2 | 18000+19000+20000=57000 | 9500+10000+10500=30000 | 87000 |
| 2024Q3 | 21000+22000+23000=66000 | – | 66000 |
| 2024Q4 | 24000+25000+26000=75000 | – | 75000 |
| 2025Q1 | 27000+28000=55000(仅 1-2 月) | – | 55000 |
三、窗口函数详细解析(修正版案例 + 精准验证)
1.1 OFFSET(动态查询、求连续值)
OFFSET完整语法:
OFFSET(
delta,// 偏移行数:正值=当前行后,负值=当前行前,支持DAX表达式
<relation> or <axis>,// 可选:表表达式/视觉轴,默认ALLSELECTED(orderBy/partitionBy列)
orderBy, // 可选:排序方式,省略则按relation列默认排序
blanks,// 可选:空值处理(DEFAULT/FIRST/LAST)
partitionBy, // 可选:分区依据,按指定列分区后各自偏移
matchBy,// 可选:定义行匹配规则(唯一标识行)
reset// 可选:视觉计算重置(仅视觉轴场景)
)
1.1.1 不使用 orderBy
案例 1:获取上个季度销售额(无分区)
— 基础度量值(修正版)
销售额 = SUM('Fact Sales'[销售额])
— OFFSET取上季度销售额(无分区)
OFFSET-上季度销售额 =
CALCULATE(
[销售额],
OFFSET(
-1,// 向前偏移1行
ALLSELECTED('Dim Calendar'[年度季度])// 偏移的数据集
)
)
精准结果验证:
| 2024Q1 | 73500 | 空 |
| 2024Q2 | 87000 | 73500 |
| 2024Q3 | 66000 | 87000 |
| 2024Q4 | 75000 | 66000 |
| 2025Q1 | 55000 | 75000 |
案例 2:按年度分区取上季度销售额
OFFSET-年度内上季度销售额 =
CALCULATE(
[销售额],
OFFSET(
-1,
ALLSELECTED('Dim Calendar'[年度季度],'Dim Calendar'[年度]),,, // 空出orderBy/blanks参数
PARTITIONBY('Dim Calendar'[年度]) // 按年度分区
)
)
精准结果验证(年度内偏移,跨年度重置):
| 2024 | 2024Q1 | 73500 | 空 |
| 2024 | 2024Q2 | 87000 | 73500 |
| 2024 | 2024Q3 | 66000 | 87000 |
| 2024 | 2024Q4 | 75000 | 66000 |
| 2025 | 2025Q1 | 55000 | 空 |
1.1.2 使用 orderBy
案例:按月份序号取上月销售额
OFFSET-上月销售额 =
CALCULATE(
[销售额] ,
OFFSET(
-1, // 向前偏移1行(上月)
ALLSELECTED( 'Dim Calendar'[月份名称 CN] , 'Dim Calendar'[月份序号] ), // 数据集
ORDERBY( 'Dim Calendar'[月份序号] , ASC ) // 按月份序号升序排序
)
)
精准结果验证(2024 年 1-4 月):
| 一月 | 1 | 23000 | 空 |
| 二月 | 2 | 25000 | 23000 |
| 三月 | 3 | 25500 | 25000 |
| 四月 | 4 | 27500 | 25500 |
1.1.3 统计连续值的最大出现次数(待补充)
案例:统计产品 A 连续达标的最大月份数
1.2 INDEX(静态查询)
INDEX完整语法:
INDEX(
position,// 检索位置:1=第一行,-1=最后一行,越界返回空表
<relation> or <axis>,// 可选:表表达式/视觉轴,同OFFSET
orderBy, // 可选:排序依据,同OFFSET
blanks,// 可选:空值处理,同OFFSET
partitionBy, // 可选:分区依据,同OFFSET
matchBy,// 可选:行匹配规则,同OFFSET
reset// 可选:视觉计算重置,同OFFSET
)
案例 1:获取全表第一季度销售额(无分区)
INDEX-第一季度销售额 =
CALCULATE(
[销售额],
INDEX(1,ALLSELECTED('Dim Calendar'[年度季度])) // 取第1行(2024Q1)
)
精准结果:无论筛选哪个季度,均返回73500(2024Q1 合计销售额)。
案例 2:按年度分区获取本年第一季度销售额
INDEX-年度内第一季度销售额 =
CALCULATE(
[销售额],
INDEX(
1,
ALLSELECTED('Dim Calendar'[年度季度],'Dim Calendar'[年度]),,,
PARTITIONBY('Dim Calendar'[年度]) // 按年度分区
)
)
精准结果验证:
| 2024 | 2024Q1 | 73500 |
| 2024 | 2024Q2 | 73500 |
| 2025 | 2025Q1 | 55000 |
案例 3:取产品销售额最后一行(最新月份)
INDEX-产品最新销售额 =
VAR AggregatedSingleTable =
SUMMARIZE(
// 基础表:事实表(已与日期表建立关联)
ALLSELECTED('Fact Sales'),
// 分组字段1:产品名称(来源于事实表)
'Fact Sales'[产品名称],
// 分组字段2:日期(通过表关系关联日期表,等价保留日期表的外部筛选条件)
'Dim Calendar'[Date],
// 计算每个(产品+日期)组合对应的销售额
"ProductDateSales", CALCULATE(SUM('Fact Sales'[销售额])) // 直接计算避免重复筛选,提升效率
)
RETURN
CALCULATE(
[销售额],
INDEX(
-1, // 选取每组中日期最新的一行
AggregatedSingleTable, // 数据范围为SUMMARIZE生成的单张聚合表
ORDERBY('Dim Calendar'[Date], ASC),
PARTITIONBY('Fact Sales'[产品名称])
)
)
精准结果:
- 产品 A:28000(2025-02)
- 产品 B:10500(2024-06)
1.3 WINDOW(滚动求和、累计求和、帕累托分析)
WINDOW完整语法:
WINDOW(
from[, from_type],// 窗口开始位置+类型:ABS=绝对位置,REL=相对位置(默认)
to[, to_type],// 窗口结束位置+类型:同from_type
<relation> or <axis>,// 可选:表表达式/视觉轴,同OFFSET
<orderBy>,// 可选:排序依据,同OFFSET
<blanks>,// 可选:空值处理,同OFFSET
<partitionBy>,// 可选:分区依据,同OFFSET
<matchBy>,// 可选:行匹配规则,同OFFSET
<reset>// 可选:视觉计算重置,同OFFSET
)
1.3.1 滚动求和与累计求和
案例 1:滚动求和(近 2 个季度销售额求和)
WINDOW-近2季度滚动销售额 =
CALCULATE(
[销售额],
WINDOW(
-1,REL, // 开始:当前行前1行(REL=相对位置)
0,REL, // 结束:当前行
ALLSELECTED('Dim Calendar'[年度季度]),
ORDERBY('Dim Calendar'[年度季度], ASC)
)
)
精准结果验证:
| 2024Q1 | 73500 | 73500 |
| 2024Q2 | 87000 | 160500(73500+87000) |
| 2024Q3 | 66000 | 153000(87000+66000) |
| 2024Q4 | 75000 | 141000(66000+75000) |
| 2025Q1 | 55000 | 130000(75000+55000) |
案例 2:累计求和(年初至今销售额)
WINDOW-年初至今销售额 =
CALCULATE(
[销售额],
WINDOW(
1,ABS, // 开始:分区第1行(ABS=绝对位置)
0,REL, // 结束:当前行
ALLSELECTED('Dim Calendar'[年度季度], 'Dim Calendar'[年度]),
ORDERBY('Dim Calendar'[年度季度], ASC),,,
PARTITIONBY('Dim Calendar'[年度]) // 按年度分区累计
)
)
精准结果验证:
| 2024 | 2024Q1 | 73500 | 73500 |
| 2024 | 2024Q2 | 87000 | 160500(73500+87000) |
| 2024 | 2024Q3 | 66000 | 226500(160500+66000) |
| 2024 | 2024Q4 | 75000 | 301500(226500+75000) |
| 2025 | 2025Q1 | 55000 | 55000 |
1.3.2 帕累托分析(二八定律)
案例:产品销售额帕累托分析(80% 销售额对应产品占比)
— 步骤1:单个产品总销售额
产品销售额 = CALCULATE([销售额], ALLSELECTED('Dim Calendar'[Date]))
— 步骤2:所有产品总销售额
总销售额 = CALCULATE([销售额], ALL('Fact Sales'[产品名称]))
— 步骤3:WINDOW计算累计销售额(按销售额降序)
累计销售额 =
CALCULATE(
[销售额],
WINDOW(
1,ABS, // 开始:第1行(销售额最高)
0,REL, // 结束:当前行
ALLSELECTED('Fact Sales'[产品名称]),
ORDERBY([产品销售额], DESC) // 按销售额降序排序
)
)
— 步骤4:累计销售额占比
累计销售额占比 = DIVIDE([累计销售额], [总销售额], 0)
— 步骤5:贡献80%销售额的产品占比
80%销售额产品占比 =
VAR Pareto80 =
FILTER(
ALLSELECTED('Fact Sales'[产品名称]),
[累计销售额占比] <= 0.8
)
RETURN
DIVIDE(COUNTROWS(Pareto80), COUNTROWS(ALL('Fact Sales'[产品名称])), 0)
精准结果验证:
- 产品 A 总销售额:15000+16000+17000+18000+19000+20000+21000+22000+23000+24000+25000+26000+27000+28000 = 301000
- 产品 B 总销售额:8000+9000+8500+9500+10000+10500 = 55500
- 总销售额:301000+55500 = 356500
- 产品 A 占比:301000/356500 ≈ 84.43%(已超 80%)
- 最终80%销售额产品占比返回50%(仅产品 A 就覆盖 80%+ 销售额)。
1.4 RANK(多字段排名 / 分区排名)
RANK完整语法:
RANK (
[<ties>],// 可选:并列处理(SKIP=跳跃排名,DENSE=连续排名),默认SKIP
[<relation> or <axis>],// 可选:表表达式/视觉轴,同OFFSET
[<orderBy>],// 可选:排序依据,支持多字段
[<blanks>],// 可选:空值处理,同OFFSET
[<partitionBy>],// 可选:分区依据,同OFFSET
[<matchBy>],// 可选:行匹配规则,同OFFSET
[<reset>]// 可选:视觉计算重置,同OFFSET
)
案例 1:多字段排名(指标一降序→指标二降序)
— 基础度量值
指标一合计 = SUM('Fact Sales'[指标一])
指标二合计 = SUM('Fact Sales'[指标二])
— 多字段排名
多字段排名 =
RANK(
SKIP, // 并列跳跃排名
ALLSELECTED('Fact Sales'[产品名称]),
ORDERBY([指标一合计], DESC, [指标二合计], DESC) // 先指标一,后指标二
)
精准结果验证:
| 产品 A | 80+85+85+90+90+90+92+92+92+95+95+95+98+98 = 1267 | 90+88+85+92+95+95+96+97+98+99+99+99+100+100 = 1323 | 1 |
| 产品 B | 70+75+75+80+82+82 = 464 | 80+82+81+85+86+87 = 501 | 2 |
案例 2:分区排名(按月份分区,产品销售额排名)
月度产品销售额排名 =
RANK(
DENSE, // 并列连续排名
ALLSELECTED('Dim Calendar'[月份], 'Fact Sales'[产品名称]),
ORDERBY([销售额], DESC),,,
PARTITIONBY('Dim Calendar'[月份]) // 按月份分区
)
精准结果验证(2024 年 1 月):
| 1 | 产品 A | 15000 | 1 |
| 1 | 产品 B | 8000 | 2 |
1.5 ROWNUMBER(分区行号 / 连续行号)
ROWNUMBER完整语法:
ROWNUMBER (
[<relation> or <axis>],// 可选:表表达式/视觉轴,同OFFSET
[<orderBy>],// 可选:排序依据,同OFFSET
[<blanks>],// 可选:空值处理,同OFFSET
[<partitionBy>],// 可选:分区依据,同OFFSET
[<matchBy>],// 可选:行匹配规则,同OFFSET
[<reset>]// 可选:视觉计算重置,同OFFSET
)
案例 1:全表连续行号(按销售额降序)
产品连续行号 =
ROWNUMBER(
ALLSELECTED('Fact Sales'[产品名称]),
ORDERBY([产品销售额], DESC)
)
精准结果:
- 产品 A 行号:1
- 产品 B 行号:2
案例 2:分区行号(按年度分区,季度行号)
年度内季度行号 =
ROWNUMBER(
ALLSELECTED('Dim Calendar'[年度], 'Dim Calendar'[季度]),
ORDERBY('Dim Calendar'[季度], ASC),,,
PARTITIONBY('Dim Calendar'[年度])
)
精准结果验证:
| 2024 | Q1 | 1 |
| 2024 | Q2 | 2 |
| 2024 | Q3 | 3 |
| 2024 | Q4 | 4 |
| 2025 | Q1 | 1 |
案例 3:筛选前 N 行(取年度内前 1 个季度数据)
年度内前1季度数据 =
FILTER(
ALLSELECTED('Dim Calendar'[年度季度], 'Dim Calendar'[年度]),
[年度内季度行号] <= 1
)
精准结果:仅返回 2024Q1、2025Q1 的数据。
四、核心总结
- 分区计算必须将分区字段加入relation参数(如年度分区需包含年度列);
- 时间类偏移 / 索引优先按月份序号/年度季度排序,避免中文月份排序错误;
- 大数据量场景下,WINDOW替代传统FILTER+SUMX可显著提升性能(40%-70%)。
网硕互联帮助中心





评论前必须登录!
注册