DBT
October 6

dbt. Макросы и Jinja. Введение. Создаём первый макрос.

В заметке кратко рассказывается об использовании макросов в dbt, приводится пример макроса, проверяющего существование таблицы в БД PostgreSQL и его вызов в модели.

По умолчанию макросы хранятся в папке проекта dbt macros. Эта директория создаётся при инициализации проекта командой dbt init. Сами макросы хранятся в файлах .sql. По сути, это переиспользуемый sql-код с Jinja. Ближайшим аналогом макросов в dbt являются user-defined functions из мира хранимого кода t-sql или pl/sql.

Давайте перейдём к примеру. Макрос ниже проверяет существование таблицы модели в БД PostgreSQL.

{% macro check_exist_table() %}
{% set check_exist_table_query %}
SELECT 1 FROM pg_catalog.pg_tables WHERE schemaname = '{{this.schema}}' 
AND tablename = '{{this.table}}'
{% endset %}

{% set results = run_query(check_exist_table_query) %}
{% set check_exist_table_flag = false %}
{% if results|length > 0 %}
{% set check_exist_table_flag = true %}
{% endif %}
{{ return(check_exist_table_flag) }}
{% endmacro %}

Строка {% macro check_exist_table() %} - здесь мы определили макрос с именем check_exist_table и без параметров.

В следующих строках определяем переменную check_exist_table_query с текстом запроса.

В строке {% set results = run_query(check_exist_table_query) %} мы выполняем этот запрос и помещаем полученный список в переменную results.

{% set check_exist_table_flag = false %} - и так понятно.

{% if results|length > 0 %} - тут мы используемый встроенный Jinja фильтр length для получения длины списка results (фильтры Jinja применяются к переменным с помощью символа |, посмотреть список всех встроенных фильтров можно тут https://jinja.palletsprojects.com/en/3.1.x/templates/#list-of-builtin-filters).

{% set check_exist_table_flag = true %} - в случае истинности условия выше переопределяем переменную флага.

{{ return(check_exist_table_flag) }} - возвращаем результат.

Давайте посмотрим, как мы можем использовать этот макрос. Сразу предупреждаю, что пример вымороченный, что в голову пришло.

Итак, создадим модель stg_test_macro1, в которой будем вызывать наш макрос.

{{
    config(
    materialized='incremental',
    alias='stg_test_macro1',
    schema='stg',
    )
}}
{% set exist_this_table_flag = check_exist_table() %}
select num from generate_series(1,10,1) num
{% if exist_this_table_flag %}
where false
{% endif %}

Эта модель создает таблицу stg_test_macro1, осуществляет первичную загрузку и при последующих запусках - ничего больше не инсертит. Т.к. таблица уже существует.

Первый запуск

10 строчек заехало.

Второй запуск - заехало 0 строк.

Проверили, макрос работает.