dbt

dbt Macros の基本: Jinja で再利用可能なロジック化

2026-04-19
NicheeLab編集部

dbt の Macro は Jinja で書く小さなテンプレート関数です。モデル内の繰り返しをなくし、倉庫ごとの差異を吸収し、チーム全体で安全に再利用できます。

この記事では、公式ドキュメントの動作に基づき、使いどころ、書き方、adapter.dispatch による方言吸収、Generic Test までを短距離で一気に押さえます。Analytics Engineer 認定の試験観点も併記します。

なぜ Macro かとコンパイルの流れ

Macro は Jinja の関数として SQL 断片を返し、モデルや他の Macro から呼び出されます。dbt は Jinja を解決してから最終的な SQL を生成し、ターゲットのデータウェアハウスへ送ります。

重複する CASE 式や正規化ルール、DDL の差分などを Macro に閉じ込めることで、保守性と方言耐性が上がります。試験では、このコンパイルと実行の段階差を言い当てられるかが頻出ポイントです。

  • コンパイル時: Jinja 展開と Macro 解決が行われる
  • 実行時: 生成された SQL が倉庫で実行される(run_query のような実行時 API はここでのみ利用可)
  • Macro は SQL を「実行」するのではなく「生成」するのが基本

dbt のコンパイル〜実行フロー(Macro/dispatch を含む)

model.sql{{ my_macro() }}Macro 解決Jinja 展開dispatchsnowflake__x / default__xcompiled SQLSELECT ...Warehouse実行 (run/test)dbt のコンパイル〜実行フロー(Macro/dispatch を含む)

最小の Macro 定義と呼び出し例

-- macros/cleaning.sql
{% macro trim_upper(col) -%}
  upper(trim({{ col }}))
{%- endmacro %}

-- models/fct_orders.sql
select
  {{ trim_upper('customer_name') }} as customer_name_norm
from {{ ref('stg_orders') }};

Macro / Model / Hook / Materialization / Operation の違い

似た用語が多いので、役割と実行タイミングで整理しておきます。Macro は他の構成要素の「中で使われる」再利用単位で、単体でスケジューリング対象になるわけではありません。

Analytics Engineer 試験では、どれがコンパイル時の仕組みで、どれが実行計画の単位かを選ばせる設問がよく出ます。

  • Model は実行単位(ノード)、Macro はテンプレート部品
  • Hook や Materialization も Macro で実装されるが、用途とトリガーが異なる
  • run-operation は Macro を手動で実行する CLI ツール
対象使いどころ実装場所/呼び出し実行タイミング
ModelSELECT を定義してテーブル/ビューを構築models/*.sql(ref で依存管理)dbt run 時に実行
Macro再利用する SQL 断片やロジックmacros/*.sql({{ macro() }} で呼ぶ)コンパイル時に展開(実行時 API は execute 時のみ)
Materializationモデルの具体的な作り方(table/view/incremental 等)macros/materializations/*.sqldbt run 時(ターゲット倉庫ごとに実行)
Hook実行前後の副作用(GRANT, ANALYZE 等)project.yml の hooks or Macroon-run-start / on-run-end / on-model-...
Operation管理系/一回きりの処理を手動実行macros/*.sql(dbt run-operation)CLI 実行時のみ

run-operation で Macro を単発実行する例

-- macros/say_hello.sql
{% macro say_hello(name) -%}
  {{ log('hello ' ~ name, info=True) }}
{%- endmacro %}

# 実行例(シェル)
# dbt run-operation say_hello --args '{"name": "NicheeLab"}'

基本構文: 引数・return・execute ガード

Macro は引数つきで定義し、SQL 文字列を返します。dbt では return 関数が使えます。Jinja の if/for で条件分岐・繰り返しが可能です。

実行時 API(run_query, load_result, log など)はコンパイル段階では未使用のため、if execute でガードします。試験では execute の意味と run_query の可用タイミングを問われがちです。

  • return で明示的に文字列を返すと読みやすい
  • 実行時 API を使うコードは if execute で囲む
  • 引数にはデフォルト値を設定できる(互換のため保守的に設計)

return と execute を使った安全な Macro

-- macros/label_case.sql
{% macro label_case(expr, label='unknown') -%}
  {% set sql %}
    case when {{ expr }} then '{{ label }}' else 'other' end
  {% endset %}
  {{ return(sql) }}
{%- endmacro %}

-- 実行時 API 例(ログ出力)
{% macro log_rowcount(model) -%}
  {% if execute %}
    {% set q %}select count(*) as c from {{ model }}{% endset %}
    {% set t = run_query(q) %}
    {% if t and t.rows and t.rows[0] %}
      {{ log('rowcount=' ~ t.rows[0]['c'], info=True) }}
    {% endif %}
  {% endif %}
  {{ return('') }}
{%- endmacro %}

パッケージ化と adapter.dispatch による方言吸収

チームや OSS と共有する Macro はパッケージ化します。呼び出しは package_name.macro_name の名前空間で行い、衝突を避けます。

倉庫ごとの差異は adapter.dispatch を使って、snowflake__macro_name のような方言別実装と default__macro_name を用意します。dbt はターゲットのアダプタに応じて最適な実装に解決します。

  • 呼び出し: {{ mypkg.some_macro(...) }}
  • 解決順: <adapter>__name があればそれを、なければ default__name
  • default 実装は常に用意しておく(試験でも推奨パターンとして問われる)

dispatch の基本パターン

-- macros/some_macro.sql(公開ラッパー)
{% macro mypkg.some_macro(arg) -%}
  {% set impl = adapter.dispatch('some_macro', 'mypkg') %}
  {{ impl(arg) }}
{%- endmacro %}

-- macros/some_macro_default.sql(既定実装)
{% macro default__some_macro(arg) -%}
  {{ return('/* default */ ' ~ arg) }}
{%- endmacro %}

-- macros/some_macro_snowflake.sql(Snowflake 実装)
{% macro snowflake__some_macro(arg) -%}
  {{ return('/* snowflake */ ' ~ arg) }}
{%- endmacro %}

-- 呼び出し
select {{ mypkg.some_macro('select 1') }};

Generic Test を Macro で作る

dbt の Generic Test は Macro として実装し、失敗行を返す SELECT を生成します。0 行なら合格、1 行以上で不合格です。

モデル名は test 実行時に渡されるので、引数で受け取り硬コードは避けます。

  • テスト Macro は SELECT で失敗行を返す
  • model と column_name を引数に取るのが定番
  • YAML から tests: - my_test: 形式で呼び出す

条件付き not_null テストの例

-- tests/not_null_if_active.sql(Macro として)
{% macro test_not_null_if_active(model, column_name) -%}
  select {{ column_name }}
  from {{ model }}
  where is_active = true
    and {{ column_name }} is null
{%- endmacro %}

# schema.yml(抜粋)
# models:
#   - name: dim_customer
#     columns:
#       - name: email
#         tests:
#           - not_null_if_active: {}

試験観点と落とし穴

Analytics Engineer 試験では、Macro の実行タイミング、adapter.dispatch の解決順、Generic Test の戻り形式などが狙われます。以下を押さえておけば取りこぼしにくいです。

実務では、ref や source といった dbt コンテキスト関数と Macro の役割を混同しないこと、倉庫依存の処理は if 文より dispatch で切り替えることが安定運用のコツです。

  • Macro はコンパイル時に展開、run_query などは実行時のみ使用可(if execute)
  • dispatch は <adapter>__name → default__name の順で解決
  • Generic Test は「失敗行を返す SELECT」である(0 行なら合格)
  • プロジェクト内の Macro は macros/*.sql に置く。共有はパッケージ化
  • 方言分岐に target.type の if を多用しない。dispatch を優先

問題で確認

Analytics Engineer

問題 1

複数の倉庫で共通の API を保ちながら、Snowflake には専用 SQL、その他には汎用 SQL を使いたい。dbt で推奨される実装はどれか。

  1. adapter.dispatch を使い、snowflake__macro_name と default__macro_name を用意する
  2. Macro 内で if target.type == 'snowflake' として分岐する
  3. Materialization を使って Macro を置き換える
  4. env_var で倉庫名を渡し、Jinja の if で切り替える

正解: A

公式の推奨は adapter.dispatch による方言別実装と default フォールバック。条件分岐は増えると保守が難しく、Materialization はモデルの作り方を司る別の機構。env_var は構成値であり、方言切り替えの一次手段ではない。

よくある質問

Macro はどこに置き、どう呼べばいいですか?

プロジェクトやパッケージの macros ディレクトリ(macros/*.sql)に置きます。同一プロジェクトなら {{ macro_name(...) }}、パッケージ経由なら {{ package_name.macro_name(...) }} で呼びます。名前衝突を避けるため、共有用途は必ずパッケージ名で呼び出すのが安全です。

Generic Test はどんな形で書けばよいですか?

Macro として実装し、失敗行を返す SELECT を生成します。0 行なら合格です。典型的には引数に model と column_name を取り、YAML の tests セクションから呼び出します。

実行時 API(run_query など)がエラーになるのはなぜ?

コンパイル段階では実行時 API は使えません。Macro 側で if execute でガードし、dbt run / test といった「実行フェーズ」でのみ呼ぶようにします。CLI の run-operation は実行フェーズなので使用可能です。

この記事で学んだ内容を問題で確認しましょう

16,000問以上の問題で実力チェック

無料で問題を解いてみる
この記事の著者

NicheeLab編集部

データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。


関連記事
dbt

dbt Model の基礎: SQL で定義する変換の最小単位

Analytics Engineer 向けに、dbt Model の定義、マテリアライゼーション、依存関係、インクリメン...

dbt

dbt Analytics Engineer 試験ガイド: 出題範囲・配点・申込の実務視点

dbt Analytics Engineer 認定の出題範囲、配点の考え方、申込から受験までの流れを、公式ドキュメントの...

dbt

dbt Cloud と dbt Core の違いと選び方:Analytics Engineer 試験に効く要点

dbt Cloud と dbt Core の機能差を、実務と資格対策の両面から整理。スケジューリング、IDE、RBAC、...

dbt

dbt プロジェクト構造ガイド: models / seeds / macros の実務レイアウト

Analytics Engineer 向けに、dbt プロジェクトのディレクトリ構造と命名規約、dbt_project....

dbt

dbt_project.yml の読み方:主要設定と命名を最短で掴む

dbt_project.yml の必須キー、命名解決(database.schema.identifier)、設定優先度...

dbtの記事一覧 (101件)
© 2026 NicheeLab All rights reserved.