wordpress不显示网站标题,江西网站设计电话,wordpress 经典推荐,上海app开发dbt宏在dbt框架内的工作方式与传统编程中的函数类似。它允许用户将特定的、通常是重复的SQL逻辑封装到可调用的命名单元中#xff0c;就像在其他编程语言中用函数来避免重复代码一样#xff1b;dbt宏定义特定业务的SQL逻辑#xff0c;然后在dbt项目中需要的地方调用该宏函数… dbt宏在dbt框架内的工作方式与传统编程中的函数类似。它允许用户将特定的、通常是重复的SQL逻辑封装到可调用的命名单元中就像在其他编程语言中用函数来避免重复代码一样dbt宏定义特定业务的SQL逻辑然后在dbt项目中需要的地方调用该宏函数实现代码重用。数据工程师利用宏在数据开发项目中维护更干净、更模块化的代码因此我们可以把dbt宏看作为SQL提供强大的、类似函数的强大功能! dbt 宏简介
dbt宏使用Jinja引擎这是Python web框架中广泛采用的模板引擎。使用Jinja可以将占位符和逻辑直接嵌入到SQL代码中使其具有动态性和模块化。在dbt宏中可以定义带有参数的SQL块然后可以在整个dbt项目中使用不同的参数重用该SQL块。
为什么要使用Jinja宏?
可重用性: 一次定义复杂逻辑然后跨多个模型使用它。可维护性: 集中逻辑以简化更新并减少错误。灵活性: 在宏中组合SQL和Python代码来处理复杂的数据转换。
简单宏示例
下面示例实现计算百分比逻辑当分母为0直接返回0反之对两数相除的结果乘以100转为百分比值
{% macro calculate_percentage(numerator, denominator) %}CASE WHEN {{ denominator }} 0 THEN 0ELSE ({{ numerator }} / {{ denominator }} * 100)END
{% endmacro %}在你的DBT模型中(例如models/my_model.sql)你现在可以调用这个宏:
SELECTorder_id,{{ calculate_percentage(total_revenue, total_cost) }} AS profit_margin
FROMorders这个SQL查询使用calculate_percentage宏计算每个订单的利润率。
Jinja 引擎介绍
通过将dbt宏与Jinja模板引擎一起使用SQL代码变得更加可重用、可维护和模块化。它让数据开发工作避免冗余、提升一致性、并简化开发过程。Jinja为宏提供了构建块因此深入理解Jinja语法是编写高质量宏的关键。接下来让我们通过创建dbt宏示例学习Jinja语法。
变量和占位符 变量 语法 {% set var_name ... %}
在dbt宏中使用Jinja时可以使用set将值赋给变量从而可以在宏中引用或重用变量。在下面的示例中定义了一个名为partners的变量其中包含代理产品的三个伙伴的列表。在本文后面回顾for循环时我们将利用这个变量。
示例
{% set partners [costco, sams_club, target] %}占位符
语法{{...}}
双花括号之间的任何内容都将被计算并替换为实际值。在dbt中这种语法最常用于函数ref()和source()。在下面的示例中引用了users关系模型。
select organization_id, min(created_at) as first_user_created_atfrom {{ ref(users) }}
group by organization_id;ref(‘users’)是一个dbt函数它被替换为dbt项目中users模型对应的关系可能为视图、表或物化视图等。当上面的代码被编译时生成的代码大致如下
select organization_id, min(created_at) as first_user_created_atfrom dbt.users
group by organization_id;注释
语法{#...#}
{#和#}之间的任何内容都是注释不会包含在最终的SQL中。通常只有在需要记录有关Jinja逻辑的特定内容时才需要这样做。应该优先描述dbt项目中宏逻辑、输入参数描述而不是代码注释。
示例
{# 这里内容仅在宏源文件中出现编译后的内容不包括注释信息 #}if 语句
语法{% if... %} … {% endif %}
这种语法用于简单的条件(if语句)来添加/删除SQL行。例如在下面的dbt宏示例中只有在满足条件时才会将where语句添加到查询中。在这种情况下条件是模型正在以增量方式运行。如果模型没有以增量方式运行where语句将被排除在查询之外。
{% if is_incremental() %}where last_update_at (select max(last_update_at) from {{ this }}){% endif %}使用Jinja可以构建非常复杂的逻辑但建议尽量保持简单易读。大多数使用dbt的人都是数据分析师他们需要了解SQL查询是如何工作的并且可能没有时间学习Jinja中所有复杂的逻辑运算符。
loop 循环
语法 {% for... %}
我们还可以使用Jinja for循环遍历列表或序列。这对dbt宏中非常有用可以实现在SQL中很难处理的逻辑。在下面的dbt宏示例中我们使用partners变量创建合作伙伴列表。对于每个合作伙伴单独存储在各自的schema中但是销售表的列完全相同。我们需要把这些表合并在一起以得到一个完整的合作伙伴销售名单。
{% set partners [costco, sams_club, target] %}{% for partner in partners %}select *,{{ partner }} as partnerfrom {{ source(partner, sales) }}{# this adds union all to all selects except for the last one #}{% if not loop.last %} union all {% endif %}{% endfor %}编译结果大致如下文
select *, costco as partner
from costco.sales union all select *, sams_club as partner
from sams_club.sales union all select *, target as partner
from target.sales 我们看到在模型文件中直接使用for循环使得代码量减少很多。如果还有其他表(如客户、库存等)需要合并只要稍微调整下上述代码即可实现重用。
宏示例实战
下面再通过两个示例加强对宏的认识提升编写宏函数能力。
生成动态条件
Jinja是生成动态SQL的强大工具。下面是一个基于jinja的宏例子它根据提供的条件生成一个WHERE子句:
{% macro generate_where_clause(column_name, value) %}{% if value is not none %}WHERE {{ column_name }} {{ value }}{% else %}-- No condition{% endif %}
{% endmacro %}在模型中使用宏
SELECT*
FROM{{ ref(customer_data) }}
{{ generate_where_clause(customer_id, customer_id) }};这种方法简化了SQL生成并在查询中提供了更大的灵活性。
动态日期范围
假设您需要根据动态日期范围筛选记录例如“最近7天”或“当前月份”。你可以创建一个宏来处理这个问题:
{% macro dynamic_date_filter(date_column, period) %}{% if period last_7_days %}{{ date_column }} BETWEEN CURRENT_DATE - INTERVAL 7 days AND CURRENT_DATE{% elif period current_month %}{{ date_column }} BETWEEN DATE_TRUNC(month, CURRENT_DATE) AND CURRENT_DATE{% else %}11 -- No filter{% endif %}
{% endmacro %}该宏接受日期列和周期作为参数返回适当的SQL筛选器。下面代码展示如何在模型中使用宏
SELECTuser_id,order_date,total_amount
FROMsales
WHERE{{ dynamic_date_filter(order_date, last_7_days) }}该查询过滤销售表只返回最近7天的记录。
宏文档
除了宏代码中的注释外还应该在宏描述文件中添加宏及和输入参数的描述。就像在模型描述文件中对列进行描述文档一样宏文档使用相同的语法。您可以在macros文件夹中创建macros.yml文件以便有专门的地方描述宏文档。下面是一个示例宏描述文件它定义了两个宏的文档:
version: 2macros:- name: cents_to_dollarsdescription: A macro to convert cents to dollarsarguments:- name: column_nametype: stringdescription: The name of the column you want to convert- name: precisiontype: integerdescription: Number of decimal places. Defaults to 2.- name: from_jsondescription: A macro to extract a nested column value out of a JSON column.arguments:- name: json_column_nametype: variantdescription: The name of the JSON column that contains the nested column.- name: nested_column_nametype: stringdescription: The name of the nested column to be extracted from the JSON column. 注意事项在编写宏之后需要在模型中使用它以确保它按预期工作。由于宏本质上是模板因此需要从模型或另一个宏调用它们以查看最终的SQL输出。 最佳实践
dbt宏的主要目标是使SQL代码更易于维护并减少冗余。随着对dbt和Jinja的使用经验不断积累创建宏的过程将更顺畅自然从而让你能够专注于复杂数据转换和模型业务实现。虽然Jinja宏功能强大但以下最佳实践仍值得借鉴:
保持简单: 避免创建难以调试或过于复杂的宏。将复杂的逻辑分解为更小的、可重用的宏。文档化宏: 给宏添加注释说明它们的用途和使用场景通过文档描述参数、数据类型及意义。测试宏: 在部署到生产环境之前要对宏进行彻底测试以确保它的行为符合预期。版本控制: 在版本控制中跟踪对宏的更改重复利用Jinja内置的宏函数、知名第三方已有宏函数后续文章会详细介绍。
总结
掌握 DBT Core 里的 Jinja 宏能够极大地提升数据工程师的工作效率。通过创建可重复使用的代码片段能够对复杂的逻辑进行标准化处理减少代码重复现象同时维护干净、高效的数据模型。我们可以从尝试简单的宏着手随着对语法越来越熟悉逐步编写更为复杂的宏。
期待您的真诚反馈更多内容请阅读数据分析工程专栏。