拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Metabase 原生 SQL 可选变量(Optional Variables)完全指南:用 `[[ ]]` 让查询子句智能显隐

Metabase 原生 SQL 可选变量Optional Variables完全指南用[[ ]]让查询子句智能显隐【免费下载链接】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导读本文聚焦 Metabase 原生NativeSQL 编辑器中的可选变量optional variables机制通过将包含变量的子句用双重方括号[[ .. ]]包裹即可让该子句在变量未赋值时自动从查询中消失、在赋值时自动还原从而用同一份 SQL 模板同时满足带筛选与不带筛选两种查询场景。读完本文你将掌握可选变量的完整语法、多可选子句的编排规则、MongoDB 中的等价写法以及用注释语法注入复杂默认值的高级技巧并了解其背后的解析与替换实现原理。什么是可选变量在 SQL 参数SQL parameters 的基础上Metabase 允许你把查询中的某个子句clause整体标记为可选。典型场景是创建一个包含变量的可选WHERE子句当用户没有给该变量提供值无论是通过筛选器控件还是 URL 参数查询依然可以正常运行效果等同于该WHERE子句根本不存在。语法非常简单把包含{% raw %}{{variable}}{% endraw %}的整个子句用[[ .. ]]包裹起来即可。当有人在筛选器控件中给变量输入了值Metabase 会把[[ ]]内的子句放回模板中并正常完成变量替换当变量没有值Metabase 会忽略整个[[ ]]子句就像它从未出现在 SQL 中一样。以下示例中如果没有给cat传值查询只统计products表中的全部行如果cat有值比如Widget则只统计 category 为 Widget 的产品{% raw %} SELECT count(*) FROM products [[WHERE category {{cat}}]] {% endraw %}从源码层面看这正是可选参数optional param的核心语义。在 native.clj 的实现注释中明确写道{% raw %}{{x}}{% endraw %}必需参数会被替换为:x的值而[[AND {{x}}]]这类可选参数如果:x未指定[[...]]内的整个子句会被替换为空字符串如果指定了则{% raw %}{{x}}{% endraw %}照常替换子句中其余部分如AND ...原样保留。实际的替换逻辑位于 substitute.clj 的substitute-optional它先尝试替换[[ ]]内的所有子参数只要其中有任何一个参数缺失opt-missing非空就整体丢弃该可选子句只有内部所有参数都齐备时才把替换后的子句拼回 SQL。前提不带可选子句时 SQL 也必须合法使用可选变量的硬性前提是当[[ ]]内的子句被移除后剩下的 SQL 仍然是一段合法、可执行的查询。这一点务必先想清楚否则变量为空时查询会直接报错。一个典型的错误写法是把WHERE关键词放在[[ ]]之外-- 这样写会报错 {% raw %} SELECT count(*) FROM products WHERE [[category {{cat}}]] {% endraw %}原因在于当cat没有值时Metabase 会按子句不存在来执行实际运行的 SQL 变成SELECT count(*) FROM products WHERE以WHERE结尾的查询显然不是合法 SQL。正确的做法是把整个WHERE子句连同关键词一起放进[[ ]]{% raw %} SELECT count(*) FROM products [[WHERE category {{cat}}]] {% endraw %}这样当cat没有值时Metabase 实际执行的是{% raw %} SELECT count(*) FROM products {% endraw %}这仍然是一段完整合法的查询。对应到实现上解析器会把[[与]]之间的内容整体识别为一个 optional token:optional-begin/:optional-end见 parse_test.cljc 中的用例SELECT * FROM toucanneries WHERE TRUE [[AND num_toucans {{num_toucans}}]]而替换阶段对缺失参数的可选子句直接产出空字符串参见 substitute_test.clj 的 optional substitution -- param not present 用例。多个可选子句至少需要一个真实的 WHERE如果要在一条查询中使用多个可选子句Metabase 要求你至少写一个普通非可选的WHERE子句随后每个可选子句都要以AND开头{% raw %} SELECT count(*) FROM products WHERE TRUE [[AND id {{id}}]] [[AND {{category}}]] {% endraw %}这里有几个要点WHERE TRUE是常用套路固定的WHERE TRUE保证查询始终合法同时让后面的多个[[AND ...]]可以自由地追加或移除互不干扰。从 parse_test.cljc 的 Multiple optional clauses 用例可以看出多个可选子句会被依次解析为多个独立的 optional tokenMetabase 会逐一独立判定是否替换。字段筛选变量field filter不带列名最后一个[[AND {{category}}]]使用的是字段筛选变量field filter注意AND后面没有写具体列名。使用字段筛选变量时必须在查询中省略列名而需要在右侧的变量配置侧栏中把该变量映射到具体字段。对于可选子句中的字段筛选变量源码中还有一处特殊处理在 substitute.clj 的substitute-field-param中处于可选子句内且没有取值的字段筛选变量会被整体忽略并最终整体移除注释明确写着 no-value field filters inside optional clauses are ignored, and eventually emitted entirely。可选变量在 MongoDB 中的写法如果你的数据库是 MongoDB同样可以用[[ ]]实现可选子句。单个可选条件{% raw %} [ [[{ $match: {category: {{cat}}} },]] { $count: Total } ] {% endraw %}多个可选筛选条件{% raw %} [ [[{ $match: {{cat}} },]] [[{ $match: { price: { $gt: {{minprice}} } } },]] { $count: Total } ] {% endraw %}注意这里的$match也遵循同样的整子句可选原则每个可选 stage包括结尾的逗号都被完整包在[[ ]]内这样当对应变量缺失时Metabase 可以干净地移除整个 stage 而不破坏 JSON 数组的结构。MongoDB 驱动同样复用了 Metabase 统一的参数解析与替换框架解析与替换逻辑位于 native.clj 所描述的metabase.query-processor.parameters.*与各驱动自己的parameters.*命名空间中保证行为与 SQL 驱动一致。在查询中直接设置复杂默认值可选变量还可以用来在查询内部为参数定义默认值方法是在可选参数结束括号的紧后方写入注释语法把默认值放在注释之后WHERE column [[ {% raw %}{{ your_parameter }}{% endraw %} --]] your_default_value其工作原理是当你给your_parameter传值时[[ ]]内的内容包括注释开头--会激活并拼回 SQL注释会把后面的your_default_value注释掉当你不传值时整个[[ ]]连同注释一起消失SQL 中只剩下默认值your_default_value。这个技巧尤其适合默认值是比较复杂的表达式例如函数的场景。下面的 PostgreSQL 示例把 Date 筛选器的默认值设为当前日期{% raw %} SELECT * FROM orders WHERE DATE(created_at) [[ {{dateOfCreation}} --]] CURRENT_DATE {% endraw %}给dateOfCreation传值时WHERE子句正常执行--把默认的CURRENT_DATE注释掉不传值时[[ ]]整段消失查询实际执行DATE(created_at) CURRENT_DATE实现默认查今天。需要特别提醒示例中的--是 SQL 的行注释语法不同数据库的注释语法不同实际使用时请替换为对应数据库支持的注释写法例如某些数据库用#或/* ... */。从解析器测试可以看到这类写法是被明确支持的——parse_test.cljc 中的用例/* [[AND num_toucans {{num_toucans}} --]] */展示了注释包围在可选子句内外的解析结果。解析与替换的边界规则避坑提示基于仓库中的解析器测试 parse_test.cljc以下几个边界行为值得注意方括号必须成对闭合像select * from foo [[where bar {{baz}}缺少]]、[[where bar {{baz]]{{与]]交叠这类不完整写法会被判定为非法输入见该文件 L130-L135 的 invalid 用例。引号内的[[与]]不受影响解析器能正确区分字符串字面量select ]] from t [[where x {{foo}}]]中]]是普通字符串不影响后续可选子句的识别L122-L123。嵌套可选子句是支持的当多个参数出现在同一个可选块中时替换逻辑会以全部齐备才保留为准则而嵌套的可选子句则各自独立判定见 substitute_test.clj 的 nested optionals 用例。小结与延伸阅读可选变量把静态 SQL 模板升级为可交互的动态查询是 Metabase 原生查询中复用度最高的能力之一。回顾核心规则用[[ 整个子句 ]]包裹变量所在的完整子句含WHERE等关键词保证去掉可选子句后 SQL 依然合法多个可选子句时先写一个真实WHERE后续每个可选子句以AND开头MongoDB 中同样适用注意把整个 stage含逗号包进[[ ]]用[[ {{param}} --]] 默认值注释技巧实现复杂默认值并按数据库替换注释符号。想深入了解参数体系的更多玩法可以继续阅读同目录下的相关文档SQL 参数、字段筛选变量、筛选器控件 与 原生 SQL 编辑入门进阶用户可进一步研读源码 native.clj 与 substitute.clj并结合 parse_test.cljc 与 substitute_test.clj 中的测试用例验证各种边界行为。【免费下载链接】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),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门