news 2026/9/12 14:07:53

Metabase substring 表达式详解:从文本中精准截取子串的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Metabase substring 表达式详解:从文本中精准截取子串的完整指南

Metabase substring 表达式详解:从文本中精准截取子串的完整指南

【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabase

substring是 Metabase 自定义表达式(Custom Expressions)中用于从文本中提取子串的核心函数。本文以substring(text, position, length)语法为主线,结合该开源仓库中 MBQL 表达式 schema 定义 与 SQL 编译实现,系统讲解其参数规则、左右截取实战技巧、支持的数据类型、底层工作原理,以及与regexExtract、SQL、Excel、Python 等工具的等价写法对比。读完本文,你将能够用substring高效处理 SKU 编号、ISO 编码、标准格式邮箱等定长格式文本的清洗与拆分。

函数语法与参数

substring的调用形式为:

substring(text, position, length)
参数说明示例
text要提取子串的源文本(字符串或字符串类型的字段引用)"user_id@email.com"
position子串起始位置,从 1 开始计数1
length要提取的字符数量,必须是正数7

例如,从邮箱地址中提取用户 ID:

substring("user_id@email.com", 1, 7)

结果为"user_id"

参数规则要点:

  • 字符串的第一个字符位于位置 1,而不是 0。这与很多编程语言(如 Python)的从 0 计数不同,但与 SQL 标准函数SUBSTRING、Excel 的MID保持一致。
  • length必须是正数,即只能正向截取固定数量的字符,不支持负数长度反向截取。

从源码结构看,MBQL 层面对substring的参数做了严格的类型约束。在 src/metabase/lib/schema/expression/string.cljc#L35-L38 中,substring被定义为catn(concatenation)类型的子句,三个参数依次为:

(mbql-clause/define-catn-mbql-clause :substring :- :type/Text [:str [:schema [:ref ::expression/string]]] [:start [:schema [:ref ::expression/integer]]] [:length [:? [:schema [:ref ::expression/integer]]]])

也就是说:str参数必须是字符串表达式,start参数必须是整数表达式,length参数是可选的整数表达式,整个表达式的返回类型为:type/Text(文本)。值得注意的是,positionlength并不强制要求是字面量数字——只要最终解析为整数表达式即可,这意味着可以嵌套length([列])count等返回整数的函数(见下文"从右侧截取")。前端表达式编译器(frontend/src/metabase/querying/expressions/test/generator.ts#L418-L424)同样将substring的参数定义为"字符串表达式 + 数字表达式 + 数字表达式"。

从左侧截取子串

当需要提取文本开头的固定长度片段时,直接设置position1即可,这正是substring最常见的用法。

假设有一张任务表,Mission ID字段形如19951113006,前 8 位是日期/编号信息,末尾 3 位是特工编号:

Mission IDAgent
19951113006006
20061114007007
19640917008008

创建一个名为Agent的自定义列,表达式为:

substring([Mission ID], 9, 3)

含义是:从第 9 个字符开始,连续取 3 个字符,得到006007008

这类"定长、有固定格式"的字符串正是substring最擅长处理的场景——SKU 编号、ISO 国家代码、标准化的邮箱地址等,只要格式一致,就能用一条表达式稳定拆分。

从右侧截取子串

substring本身不直接支持"倒数第几个字符开始"的写法,但可以通过嵌套length函数把"从右往左数"换算成"从左往右的起始位置"。通用公式为:

1 + length([column]) - position_from_right

其中position_from_right表示从右往左数起始位置(即倒数第几个字符),length([column])返回整列文本的总长度。

仍以上述任务表为例,Agent 是末尾 3 位字符。position_from_right = 3,代入公式:

substring([Mission ID], (1 + length([Mission ID]) - 3), 3)

19951113006而言,length为 11,起始位置为1 + 11 - 3 = 9,即从第 9 个字符起取 3 位,结果同样是006。表内计算过程如下:

Mission IDAgent(substring 结果)
19951113006006
20061114007007
19640917008008

这里的length也是 Metabase 的内置文本函数,其 MBQL 定义返回:type/Integer(见 src/metabase/lib/schema/expression/string.cljc#L20-L21),因此可以被substring直接当作整数表达式参数使用,印证了上面提到的"参数可以是表达式"这一特性。

接受的数据类型

substring只接受文本(String)类型作为第一个参数,其余数据类型均不支持:

数据类型是否可与substring配合
String
Number
Timestamp
Boolean
JSON

因此,如果源字段是数字、日期、布尔或 JSON 等类型,需要先用类型转换表达式将其转为文本,再交给substring截取。

底层实现:substring 如何被编译成 SQL

理解substring的底层编译过程,有助于判断它在不同数据库上的行为差异。Metabase 的查询表达式会先被解析为 MBQL(Metabase BI Query Language)语法树,再经由各数据库驱动编译为对应方言的 SQL。

在通用 SQL 驱动层(src/metabase/driver/sql/query_processor.clj#L1386-L1390)中,substring被编译为标准的 SQLSUBSTRING函数:

(defmethod ->honeysql [:sql :substring] [driver [_ _opts arg start length]] (if length [:substring (->honeysql driver arg) (->honeysql driver start) (->honeysql driver length)] [:substring (->honeysql driver arg) (->honeysql driver start)]))

注意这里对可选参数length的分支处理:当未提供length时,生成的 SQL 只带两个参数(SUBSTRING(text, start),表示从起始位置取到末尾);提供length时生成三参数形式(SUBSTRING(text, start, length))。

部分数据库方言需要单独适配。例如 SQLite 没有三参数的SUBSTRING,Metabase 在 src/metabase/driver/sqlite.clj#L414-L418 中将其改写为SUBSTR

(defmethod sql.qp/->honeysql [:sqlite :substring] [driver [_ _opts arg start length]] (if length [:substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver start) (sql.qp/->honeysql driver length)] [:substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver start)]))

MySQL 驱动(src/metabase/driver/mysql.clj)则使用substring_index系列函数进行适配。也就是说:你在 Metabase 表达式中写下的substring([Mission ID], 9, 3)是数据库无关的统一写法,实际执行时由 Metabase 按目标数据库自动翻译成SUBSTRINGSUBSTR等对应方言。

限制与替代方案

substring按"固定字符数"提取文本,因此有两个天然局限:

  1. 无法基于模式匹配提取:当截取规则比较复杂(如"找到最后一个00之后的所有字符")时,substring无能为力,此时应改用regexExtract配合正则表达式。
  2. 不处理空白字符:如果只是想去掉文本两端的多余空格,substring不是合适工具,应改用trim/lTrim/rTrim系列表达式——这三个函数在 src/metabase/lib/schema/expression/string.cljc#L8-L10 中被统一定义为返回文本类型的一元函数。

与其他工具/函数的等价写法

RegexExtract:模式驱动的提取

若截取规则依赖模式而非固定位置,可用regexExtract实现同样的效果。例如要提取19951113006中最后一个00及其之后的内容:

regexExtract([Mission ID], ".+(00.+)$")

其结果与substring([Mission ID], 9, 3)一致。二者取舍原则:文本格式固定 → 用substring(简单、可读性强);格式多变或需按模式匹配 → 用regexExtract(灵活、支持正则)

SQL

当你在 Notebook 编辑器中运行查询时,Metabase 会把图形化的查询设置(筛选、汇总、自定义列等)转换为 SQL 并在数据库中执行。如果上述示例数据存放在 PostgreSQL 中:

SELECT mission_id, SUBSTRING(mission_id, 9, 3) AS agent FROM this_message_will_self_destruct;

这段 SQL 与 Metabase 表达式substring([Mission ID], 9, 3)完全等价——这也正对应前面提到的"通用 SQL 驱动将 MBQLsubstring编译为标准SUBSTRING"的实现。

Spreadsheets(Excel / Google Sheets)

如果数据在电子表格中,且Mission ID位于 A 列:

=mid(A2,9,3)

Excel 的MID函数与 Metabasesubstring等价,同为"从第 9 个字符起取 3 个字符",且二者都从位置 1 开始计数。

Python(pandas)

假设数据在名为df的 DataFrame 中:

df['Agent'] = df['Mission ID'].str.slice(8, 11)

str.slice(8, 11)提取从索引 8(含)到索引 11(不含)的字符,即第 9~11 个字符,与substring([Mission ID], 9, 3)结果相同。注意 Python 字符串索引从 0 开始,因此这里写的是8, 11而不是9, 3,这也提醒你:跨工具迁移时务必留意计数基准的差异。

进一步阅读

  • Metabase 自定义表达式完整列表
  • 自定义表达式使用指南
  • regexExtract 正则提取表达式详解
  • 表达式底层编译链路:MBQL 字符串函数 schema、SQL 查询处理器、SQLite 驱动实现

【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabase

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 14:07:11

Python实战:NASA API数据获取与可视化全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 14:06:33

32KB MCU实现边缘AI:ML-KWS-for-MCU静态架构解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 14:03:33

ToF相机深度解析:光机电算协同系统设计与实战调优

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 13:57:26

SpringBoot家庭理财系统设计与实现

1. 项目概述:SpringBoot家庭理财系统设计背景这个基于SpringBoot的家庭理财管理系统,本质上是一个面向个人和家庭的轻量级财务数字化解决方案。在移动支付普及和消费多元化的今天,传统的手工记账方式已经难以满足现代家庭对财务管理的实时性、…

作者头像 李华