ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Metabase SQL Snippets 完整指南:在原生查询编辑器(Native Editor)中复用与标准化 SQL

Metabase SQL Snippets 完整指南:在原生查询编辑器(Native Editor)中复用与标准化 SQL Metabase SQL Snippets 完整指南在原生查询编辑器Native Editor中复用与标准化 SQL【免费下载链接】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/metabaseSnippets代码片段是 Metabase 原生查询Native Query中用于保存和复用 SQL 代码片段的核心机制。本指南以 docs/questions/native-editor/snippets.md 为骨架结合仓库中 src/metabase/native_query_snippets 模块的源码实现完整讲解 Snippets 的创建、使用、编辑、归档、参数化与权限模型。读完本文你将掌握如何用 Snippets 固化复杂 JOIN、标准化 KPI 口径与通用过滤器并理解其底层存储与解析原理从而安全地在团队内推广 SQL 复用。Snippets 是什么Snippets是可复用的 SQL 或原生查询代码块。任何拥有原生编辑器权限的用户都可以创建和编辑 Snippets创建后对组织中所有原生查询编写者可见可用。例如如果你的查询经常涉及多张表的联表可以把这些表的 JOIN 代码保存为一个 Snippet这样你以及组织中的其他人就能在多份问题Questions中重复使用这段代码。Snippets 的典型用途包括标准化 KPI 与过滤器像查询构建器Query Builder中的 指标Metrics 和 分段Segments 一样你可以用 SQL 在 Snippet 中精确固化收入怎么算什么算活跃用户这类口径并在所有 SQL 问题中统一引用。通用过滤器集合把一组可复用的过滤器定义成 Snippet供多个 SQL 问题共享。从实现上看Snippet 对应应用数据库native_query_snippet表中的一条记录。其数据模型定义在 src/metabase/native_query_snippets/schema.clj核心字段包括字段类型说明idinteger主键namestring名称全局唯一含归档片段descriptionstring / null描述contentstringSQL 代码内容creator_idinteger创建者用户 IDarchivedboolean是否已归档collection_idinteger / null所属收藏夹Snippet 专属命名空间entity_idstring实体稳定 ID用于序列化/同步template_tagsmap / null解析出的模板标签参数、片段引用等其中template_tags并非用户手工填写而是由后端在保存时根据content自动解析生成的这一点将在下文底层原理部分详述。创建 Snippet方式一从编辑器选中代码保存在原生编辑器中点击右上角 New SQL query或 New Native query打开原生编辑器。编写 SQL 或原生代码然后高亮选中想要保存复用的代码段。该代码段不必是完整查询例如可以选中orders AS o LEFT JOIN products AS p ON o.product_id p.id WHERE p.category {{category}}右键点击高亮的代码段选择Save as snippet创建 Snippet。为 Snippet 命名并填写描述。Snippet 名称必须唯一包括已归档的片段也不能重名。保存。在 Snippet 内部你可以使用SQL 参数如{{param}}对其他 Snippet 的引用如{{snippet: orders}}Metabase 会自动检测并禁止循环引用对已保存问题或模型的引用如{{#123-orders-model}}。关于命名后端 api.clj 中的校验逻辑NativeQuerySnippetNameschema定义于 native_query_snippet.clj明确了命名约束名称不能包含}字符也不能以空格开头。这与{{snippet: 名称}}的引用语法直接相关——名称中若含}会破坏引用块的解析。对应的 API 测试 api_test.clj 验证了这些校验规则。方式二从 Snippet 侧边栏创建打开原生编辑器 New SQL query或 New Native query。点击编辑器上方的Snippets按钮打开 Snippet 侧边栏。在侧边栏中输入要保存为 Snippet 的代码。保存。使用 Snippet在查询中插入已保存的 Snippet会生成一个{{snippet: }}引用SELECT * FROM {{snippet: orders and products}}在原生代码中输入{{snippet: }}时Metabase 会弹出自动补全选项列出当前有权限看到的 Snippet。执行查询时Metabase 在后台把 Snippet 引用替换为对应的 SQL。对空白字符敏感Metabase 对 Snippet 引用中的空格很敏感应写成{{snippet: Products}}——{{与snippet之间不能有空格而:与 Snippet 名称之间必须有一个空格。除了手动输入也可以从侧边栏插入点击编辑器上方的Snippets按钮打开侧边栏。搜索 Snippet。注意搜索结果只包含你有权限查看的片段。悬停到某个 Snippet点击其名称左侧的箭头即可插入到查询中。别名注意事项如果 Snippet 中使用了别名那么更大的查询中也必须使用该别名。例如 Snippet 将products别名为p则片段外部的代码需要以p来引用该表的列如p.column_name。预览带 Snippet 的完整查询Metabase 会在 SQL 编辑器中保留{{snippet: }}引用不会在编辑器中直接显示替换后的完整查询。如需查看真正发送给数据库的完整 SQL点击编辑器上方的眼睛Eye图标即可预览。从实现角度看替换发生在查询执行阶段意味着 Snippet 本质上是**查询时展开query-time expansion**而非保存时固化。这也解释了为何修改一个 Snippet 会影响所有引用它的问题——它们存储的是对 Snippet 的引用而非拷贝。编辑 Snippet编辑 Snippet 是批量修改多个问题的有效方式。例如你把从表 X、Y、Z 拉取用户数据的 SQL 保存为User Data片段当需要调整取数逻辑如增加一个列或一张表时只需更新该 Snippet 的 SQL所有引用User Data的问题都会自动获得更新后的代码。编辑步骤点击编辑器上方的Snippet图标打开侧边栏。搜索 Snippet。搜索结果只包含你有权限编辑的片段。点击 Snippet 名称右侧的向下箭头然后点击Edit。你可以修改代码、名称和描述。编辑时有两点需要特别注意修改名称改名会更新每个引用该 Snippet 的问题中的片段名称不会破坏已有问题的引用但会破坏引用该 Snippet 的其他 Snippet。从源码看这背后的机制是保存时后端会按名称重新解析{{snippet: 名称}}引用见下文循环引用检测重命名后旧名称不再匹配任何已存在的 Snippet因此上游片段的引用会失效。修改代码修改 Snippet 代码影响面极大——如果代码有误会破坏所有使用该 Snippet 的问题。保存到已有 Snippet 之前务必先充分测试代码。归档与取消归档 Snippet归档可以让过时或不太相关的 Snippet 不再干扰日常使用。归档某个 Snippet 后该片段不再出现在 Snippet 自动补全下拉列表中该片段不再出现在侧边栏的 Snippet 列表中不会影响任何已引用该 Snippet 的查询——即使归档片段仍可能活跃在问题中。归档步骤点击编辑器上方的Snippet图标打开侧边栏。搜索 Snippet。点击 Snippet 名称右侧的向下箭头然后点击Edit。点击Archive。你可以从侧边栏底部的已归档入口访问归档的 Snippet。Metabase没有删除 Snippet 的功能但可以随时归档/取消归档。两个 Snippet 不能重名因为即使片段被归档它仍可能被问题引用重名会导致引用歧义。后端对归档的实现是native_query_snippet表中的archived布尔标志。db.clj 中的snippets-by-archived函数按该标志查询并按名称大小写不敏感排序返回API 层 api.clj 的GET /api/native-query-snippet端点接受archived查询参数来区分归档/未归档列表。SQL 参数SQL Parameters在 Snippet 中的使用你可以在 Snippet 中引用 SQL 参数。例如保存如下代码WHERE {{created_at}} AND category {{category}} GROUP BY {{time_grouping}}当带参数的 Snippet 被加入 SQL 查询后Metabase 会为 Snippet 中的参数显示对应的控件widget。在查询的Variables 侧边栏中你可以为来自 Snippet 的参数指定类型、关联的列以及默认值。参数值由问题Question决定而非 SnippetSnippet 参数的设置在查询层面定义不随 Snippet 共享。也就是说同一个 Snippet 被放进不同查询时其参数可以映射到不同的列。例如 Snippet 内容为WHERE {{created_at}}你可以在问题 A 中让该参数映射到CREATED_AT列在问题 B 中让同一参数映射到另一列如CANCELED_AT。如果多个 Snippet 中含有同名参数使用这些 Snippet 的问题只会保留该参数的一份实例。例如{{snippet: 1}}中包含参数{{var}}{{snippet: 2}}也包含参数{{var}}那么问题中只会显示一个{{var}}参数其取值同时应用于两个 Snippet。Snippet 中的表变量Table Variables还可以在 Snippet 中使用表变量把通用查询写成一次然后在不同问题中插入不同的表SELECT COUNT(*) FROM {{table}}跨问题共享参数Snippets 还可以在多个 SQL 问题之间共享参数包括嵌套问题基于其他问题的结果构建的问题。例如你有一个按日期统计订单Orders by date的问题用{{start_date}}过滤订单然后又创建了按产品统计收入Revenue by product的问题它使用前者的结果。为了让两个问题持续使用同一个{{start_date}}参数可以把包含该参数的 SQL 从Orders by date移动到 Snippet 中并让两个问题都引用该 Snippet。这样两个问题会暴露同一个参数仪表盘上一个日期筛选器即可同时控制使用该 Snippet 的两张卡片。Snippet 权限任何对至少一个已连接数据库拥有原生编辑器权限的用户都可以查看 Snippet 侧边栏并且可以创建、编辑、归档/取消归档所有Snippet——即使某些 Snippet 原本是用于该用户没有 SQL 编辑权限的数据库。这一宽松行为与社区版CE的权限实现一致。在 permissions.clj 中CE 的can-read?、can-write?、can-create?、can-update?都归结为has-any-native-permissions?即判断当前用户是否对任意数据库拥有:perms/create-queries创建查询类型的权限。CE 因此没有按片段细分的权限控制。部分套餐EE提供额外功能将 Snippets 组织到文件夹并对文件夹设置权限。详见文档 Snippet 文件夹与权限。从代码结构看EE 通过defenterprise覆写了 CE 的权限实现metabase-enterprise.snippet-collections.models.native-query-snippet.permissions实现基于收藏夹的细粒度控制。底层原理Snippet 的存储、解析与展开数据模型与 APISnippet 的后端模块位于 src/metabase/native_query_snippets包括core.clj模块入口导出 API 与模型的关键函数list-native-query-snippets、get-native-query-snippet、add-template-tags、has-any-native-permissions?等api.cljREST API 端点/api/native-query-snippetdb.clj所有应用数据库查询基于 Toucan 2schema.clj数据与更新请求的 Malli schemamodels/native_query_snippet.clj模型实体、生命周期钩子与序列化serdes。REST API 端点包括方法路径说明GET/api/native-query-snippet列出当前用户可读的 Snippet支持archived参数GET/api/native-query-snippet/:id获取单个 SnippetPOST/api/native-query-snippet创建 Snippet校验名称唯一性与命名规则PUT/api/native-query-snippet/:id更新 Snippet描述/收藏夹/归档状态/内容/名称相关 API 测试位于 test/metabase/native_query_snippets/api_test.clj覆盖了列表、读取、创建校验、重名报错、creator_id不可修改等行为。模板标签解析add-template-tags保存或更新 Snippet 时后端会自动解析content中的模板标签template tags这是理解 Snippet 引用机制的关键。核心函数add-template-tags定义于 native_query_snippet.clj用lib/recognize-template-tags解析内容识别出所有模板标签如{{snippet: FilterA}}或{{var}}对{{snippet: ...}}类型的引用标签按名称在数据库中查找目标 Snippet 的 IDsnippet-id-by-name若名称匹配到已存在片段使用其 ID 建立稳定的引用若目标片段已被重命名导致名称失配则沿用旧标签中保留的snippet-id从而保证引用在目标重命名后依然稳定若二者都不存在则保留无snippet-id的标签引用尚不存在片段。该逻辑在t2/define-before-insert与t2/define-before-update钩子中触发并发布:event/snippet-create、:event/snippet-update、:event/snippet-delete事件见 native_query_snippet.clj。测试 models/snippet_persistence_test.clj 对此做了验证。循环引用检测文档中提到Metabase 会检测并禁止循环引用。从实现看Snippet 引用通过模板标签的snippet-id关联到目标片段解析与校验发生在模板标签识别阶段lib/recognize-template-tags及add-template-tags的解析流程可以推断 Metabase 会在识别/校验阶段检测引用链拒绝会形成环的引用组合避免查询展开时无限递归。查询时展开当执行包含{{snippet: 名称}}的查询时查询处理器会把引用替换为对应 Snippet 的content同时合并参数template tags。这一点由查询处理器中模板标签替换机制保证相关测试可参见 test/metabase/query_processor/middleware/resolve_referenced_test.clj 与 test/metabase/driver/sql/parameters/substitute_test.clj。序列化与远程同步NativeQuerySnippet支持 Metabase 的序列化serdes机制可随收藏夹导出/导入native_query_snippet.clj 定义了导出查询、字段副本archived/content/description/entity_id/name、存储路径snippets命名空间以及重名冲突时的自动重命名追加(copy)。为什么使用 Snippets标准化Standardization你的组织如何定义热销产品是按销量还是按平均评分大于 4 的评论数你可以把热销产品的定义固化在{{snippet: popular products}}中让所有引用它的问题都自动填充该代码。日后口径需要调整只需更新 Snippet 的 SQL改动会自动传播到所有引用它的问题。这与分段Segments命名的一组过滤器和指标Metrics命名计算的作用类似Snippets 从 SQL 层面保证跨团队的正确性与一致性。效率Efficiency是否经常复制粘贴 SQL是否记不清外键与表的对应关系把复杂的 JOIN 写一次、存成 Snippet需要时直接调用即可。学习EducationSnippets 可以让 SQL 新手乃至资深分析师接触到组织的规范 SQLcanonical SQL学习更高效、更复杂的写法。阅读、复制并基于优质代码进行二次开发是提升技能的最佳途径之一。人们可以复制片段代码、修改得到不同结果再另存为新 Snippet 供他人使用从而沉淀组织的 SQL 知识库。进一步学习深入理解 Snippets、Saved Questions 与 Views 三者的适用场景参见原生编辑器系列文档的编写 SQL、引用已保存问题与模型与表变量Snippet 文件夹与权限的高级用法见权限文档若 SQL 查询遇到问题可查阅 SQL 故障排查指南后端实现与测试可继续阅读 src/metabase/native_query_snippets 与 test/metabase/native_query_snippets 目录。【免费下载链接】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),仅供参考
返回列表