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, осуществляет первичную загрузку и при последующих запусках - ничего больше не инсертит. Т.к. таблица уже существует.