窗口函数

更新时间:
复制 MD 格式

窗口函数是一种在指定分区内对数据进行排名或偏移取值的函数,它在不改变查询行数的前提下为每行数据附加计算值。窗口函数在数据库中完成计算,可结合过滤器面板实现组内TopN等分析场景。本文为您介绍窗口函数的语法、使用方法与典型应用场景。

使用限制

窗口函数仅支持以下数据源,且数据源版本需满足最低版本要求。

数据源

是否支持

最低版本

MySQL

支持

8.0(5.7及以下不支持)

AnalyticDB MySQL

支持

3.0(仅支持 XIHE 引擎)

PostgreSQL

支持

9.4

ClickHouse

支持

21.1

MaxCompute

支持

全版本

Oracle

支持

11g

Hive

支持

2.1.0

SQL Server

支持

2012

此外,窗口函数还有以下使用限制:

  • 数据建模:关系模型(多逻辑表数据集)不支持窗口函数。若需使用,请调整为物理层建模。

  • 图表:明细表、趋势分析表、多维分析表不支持窗口函数。

  • 函数嵌套:窗口函数不支持与LOD函数嵌套使用,也不支持与窗口函数嵌套使用。

  • 分区字段:窗口函数中使用的分区字段必须拖入图表的维度中,否则数据库无法计算。

  • 偏移行数:WINDOW_LAG和WINDOW_LEAD的偏移行数必须为正整数,且不超过999999999。

  • 总计与小计:含窗口函数的字段不支持总计、小计,对应值显示为“-”。

背景介绍

在日常分析中,组内排名(如各区域利润排名前5的城市、各类目销售额TopN)、同比环比(如每个产品的上月销售额)、首末值对比(如各类目首日销售额)等需求十分常见。

此类需求也可以通过表计算实现,但表计算在内存中执行,受取数行数上限约束,数据量大时结果可能不完整。窗口函数则在数据库中直接完成排名、偏移等计算,再配合过滤器面板过滤,仅返回满足条件的数据行,可减少数据传输量并提升大数据量场景下的分析性能。

使用场景

窗口函数适用于以下典型分析场景:

场景

示例

对应函数

排名分析

各类目销售额排名、各区域业绩排行。

WINDOW_ROW_NUMBER、WINDOW_RANK、WINDOW_DENSE_RANK

同比环比

对比当月与上月、下月的销售额。

WINDOW_LAG、WINDOW_LEAD

首末值分析

各类目第一天或最后一天的销售额。

WINDOW_FIRST_VALUE、WINDOW_LAST_VALUE

组内TopN

仅保留各分区内排名前N的数据行。

排名函数 + 过滤器面板

语法说明

窗口函数采用与LOD函数一致的分段式语法,以花括号({})包裹参数,各段之间以英文冒号分隔。窗口函数通过分区字段将数据划分为若干分区,并在每个分区内按排序表达式进行排名或偏移取值。各参数说明如下:

参数

说明

分区字段

指定分区(分组)的一个或多个维度,使用逗号分隔,可为空(表示全局排名)。

排序表达式

指定排序的字段或聚合表达式,支持ASC(升序)或DESC(降序),默认为ASC。支持多个字段,使用逗号分隔。

取值字段

指定要取值的表达式,必须为聚合字段或聚合表达式。仅偏移函数与首末值函数需要该参数。

偏移行数

指定向前或向后偏移的行数,必须为正整数。仅偏移函数需要该参数。

WINDOW_ROW_NUMBER

WINDOW_ROW_NUMBER用于对分区内的数据进行行号排名,不存在并列,每行分配唯一编号。

语法

WINDOW_ROW_NUMBER{<分区字段> : <排序表达式>}

定义

对分区内的数据进行“行号排名”,即:不存在并列,每行唯一编号。

输出

整数

示例

WINDOW_ROW_NUMBER{[区域]: BI_SUM([订单金额]) DESC}

对各个区域的销售额进行降序的行号排名,如 (6, 9, 9, 14) -> (4, 2, 3, 1)。

WINDOW_RANK

WINDOW_RANK用于对分区内的数据进行跳跃排名,允许并列,并列后跳过后续编号。

语法

WINDOW_RANK{<分区字段> : <排序表达式>}

定义

对分区内的数据进行“跳跃排名”,即:允许并列,并列后跳过编号。

输出

整数

示例

WINDOW_RANK{[区域]: BI_SUM([订单金额]) DESC}

对各个区域的销售额进行降序的跳跃排名,如 (6, 9, 9, 14) -> (4, 2, 2, 1)。

WINDOW_DENSE_RANK

WINDOW_DENSE_RANK用于对分区内的数据进行密集排名,允许并列,并列后不跳过编号。

语法

WINDOW_DENSE_RANK{<分区字段> : <排序表达式>}

定义

对分区内的数据进行“密集排名”,即:允许并列,并列后不跳过编号。

输出

整数

示例

WINDOW_DENSE_RANK{[区域]: BI_SUM([订单金额]) DESC}

对各个区域的销售额进行降序的密集排名,如 (6, 9, 9, 14) -> (3, 2, 2, 1)。

WINDOW_LAG

WINDOW_LAG用于取分区内当前行之前第N行的值,若超出分区范围则返回NULL。

语法

WINDOW_LAG{<分区字段> : <排序表达式> : <取值字段> : <偏移行数>}

定义

取分区内,当前行之前第N行的值,若超出分区范围则返回NULL。

输出

数值

示例

WINDOW_LAG{[产品]: [月份] ASC: BI_SUM([销售额]): 1}

以产品为分区,按月份升序排列,取前1行的销售额(即上一月销售额)。

WINDOW_LEAD

WINDOW_LEAD用于取分区内当前行之后第N行的值,若超出分区范围则返回NULL。

语法

WINDOW_LEAD{<分区字段> : <排序表达式> : <取值字段> : <偏移行数>}

定义

取分区内,当前行之后第N行的值,若超出分区范围则返回NULL。

输出

数值

示例

WINDOW_LEAD{[产品]: [月份] ASC: BI_SUM([销售额]): 1}

以产品为分区,按月份升序排列,取后1行的销售额(即下一月销售额)。

WINDOW_FIRST_VALUE

WINDOW_FIRST_VALUE用于取分区内排序后第一行的值。

语法

WINDOW_FIRST_VALUE{<分区字段> : <排序表达式> : <取值字段>}

定义

取分区内排序后第一行的值。

输出

数值

示例

WINDOW_FIRST_VALUE{[类目]: [日期] ASC: BI_SUM([销售额])}

以类目为分区,按日期升序排列,取每个分区第一行的销售额(即各类目第一天的销售额)。

WINDOW_LAST_VALUE

WINDOW_LAST_VALUE用于取分区内排序后最后一行的值。

语法

WINDOW_LAST_VALUE{<分区字段> : <排序表达式> : <取值字段>}

定义

取分区内排序后最后一行的值。

输出

数值

示例

WINDOW_LAST_VALUE{[类目]: [日期] ASC: BI_SUM([销售额])}

以类目为分区,按日期升序排列,取每个分区最后一行的销售额(即各类目最后一天的销售额)。

操作步骤

  1. 在数据集编辑页面,单击新建计算字段。

    image

  2. 填写字段名称(①),在字段表达式中输入窗口函数表达式(②),并配置字段类型等配置项(③)。

    例如,字段名称填写“区域利润排行”,字段表达式填写:WINDOW_ROW_NUMBER{[区域]: BI_SUM([利润金额]) DESC}。

    image

  3. 单击确定完成新建。

  4. (可选)如需筛选组内TopN,将该字段拖入过滤器面板并设置过滤条件。

    例如,设置为小于或等于5,即仅保留各分区内排名前5的数据行。

    image

  5. 使用该字段创建仪表板图表,即可查看窗口函数的计算结果。

应用案例

各区域利润排名前5的城市

分析各区域利润金额最高的前5个城市时,使用窗口函数可一次计算所有区域的排名,再通过过滤器筛选。

  1. 新建计算字段“区域利润排名”,字段表达式填写:WINDOW_ROW_NUMBER{[区域]: BI_SUM([利润金额]) DESC}。

    image

    即以区域为分区,按利润金额合计降序排列,为每行分配唯一排名。

  2. 创建交叉表,将区域、城市拖入行区域,将利润金额和区域利润排名拖入列区域。

  3. 将区域利润排名拖入过滤器面板,设置过滤条件为小于或等于5。

    image

  4. 单击更新,交叉表中仅展示各区域中利润排名前5的城市。

    image

各产品类型销售额排行(允许并列)

分析各类目下产品的销售额排名且允许并列时,使用WINDOW_RANK或WINDOW_DENSE_RANK代替WINDOW_ROW_NUMBER。

  1. 新建计算字段“各产品类型销售额排行”,字段表达式填写:WINDOW_RANK{[产品类型]: BI_SUM([销售金额]) DESC}。

    image

    即以类目为分区,按销售额合计降序排列,允许并列且并列后跳号。

  2. 创建交叉表,将产品类型、产品名称拖入行区域,将销售金额和各产品类型销售额排行拖入列区域。

  3. 单击更新,订单金额相同的产品获得相同排名编号。

    image

说明
  • WINDOW_RANK:并列后跳号,如 1、2、2、4。

  • WINDOW_DENSE_RANK:并列后不跳号,如 1、2、2、3。

各城市的上月销售额(环比基础)

在展示各产品每月销售额的同时展示其上月销售额,可用于计算环比增长率。

  1. 新建计算字段“各城市上月销售额”,字段表达式填写:WINDOW_LAG{[城市]: [订单月份] ASC: BI_SUM([订单金额]): 1}。

    image

    即以城市为分区,按月份升序排列,取当前行前1行的销售额。

  2. 创建交叉表,将城市、订单月份拖入行区域,将订单金额和各城市上月销售额拖入列区域。

  3. 单击更新,各产品的首月无上月数据,显示为空,其余月份展示对应的上月销售额。

    image

如需计算环比增长率,可再新建计算字段,表达式为:(BI_SUM([销售额]) - [上月销售额]) / [上月销售额]。

常见问题

  • 窗口函数和表计算有什么区别?

    表计算在内存中执行,数据库返回全量数据后再计算排名;窗口函数在数据库中执行,配合过滤器面板可在数据库侧完成组内TopN过滤,仅返回满足条件的数据行,大数据量场景下性能更优。

  • 分区字段可以为空吗?

    可以。分区字段为空时表示全局排名,即对整个结果集统一计算,如 WINDOW_ROW_NUMBER{: BI_SUM([销售额]) DESC}。

  • 如何实现组内TopN?

    分两步:先新建排名计算字段,如 WINDOW_ROW_NUMBER{[类目]: BI_SUM([销售额]) DESC};再将该字段拖入过滤器面板并设置过滤条件,如小于或等于5。

  • 为什么MySQL数据源提示不支持窗口函数?

    MySQL从8.0版本开始支持窗口函数。请检查数据源版本,若低于8.0,请升级数据源版本或更换数据源。

  • 窗口函数可以和LOD函数一起使用吗?

    支持在同一查询中分别使用LOD函数字段和窗口函数字段,两者各自独立计算。但不支持在窗口函数表达式内嵌套LOD表达式。