dbt

Jinja の基礎: dbt で最低限押さえる文法

2026-04-19
NicheeLab編集部

dbt は Jinja2 を使って SQL をテンプレート化し、コンパイル時に最終的な SQL を生成します。つまり Jinja は「実行前に展開されるルール」であり、正しく理解すればモデル定義が簡潔かつ再利用可能になります。

本稿では、Analytics Engineer 試験と日常運用の両方で必須となる Jinja の最小限文法と dbt 固有コンテキスト(ref, source, var, env_var, config, マクロ)を、誤りやすいポイントとともに整理します。

Jinja はどこで動くか: dbt の評価タイミング

dbt はモデルを実行する前に Jinja を評価し、最終的な SQL を生成します。依存関係の解決(ref/source)やマクロ展開はこの段階で行われます。Jinja 自体はデータベースで動くのではなく、dbt(ローカルないし実行環境)で処理されます。

評価タイミングは大きく「パース/コンパイル中」と「実行時のマクロ呼び出し」に分かれます。データベース接続が必要な run_query は実行時にのみ安全に呼び出せます。一方で、ref/source/var/env_var/config はモデルやマクロのテンプレート内で一般的に利用されます。

  • Jinja はコンパイルフェーズで SQL に展開される(DB 上で解釈されない)
  • ref は依存グラフとスキーマ名テーブル名の解決を担う
  • run_query はマクロ内など実行時にのみ使用し、パースのみの文脈では避ける
フェーズできること代表 API/構文注意点
パース/コンパイルテンプレート展開・依存解決ref, source, var, env_var, configDB への問い合わせは不可
実行(マクロ内)補助的なクエリ実行run_query使い所を限定。モデル本体の SQL 生成に混ぜない
DB 実行最終 SQL の実行純粋な SQLJinja はここでは既に展開済み

dbt における Jinja の評価と実行の流れ

開発者のSQL+Jinjadbt コンパイルJinja評価最終SQL依存解決済データベースで実行dbt における Jinja の評価と実行の流れ

最小例: ref と Jinja 展開のイメージ

-- models/orders_enriched.sql
select
  o.id,
  o.customer_id,
  c.segment
from {{ ref('stg_orders') }} as o
left join {{ ref('dim_customers') }} as c
  on o.customer_id = c.customer_id;

基本記法: 変数、式、フィルタの最短セット

Jinja の区切りは3種類だけ押さえれば十分です。{{ }} は値(式/変数)の出力、{% %} は制御構文(if, for, set など)、{# #} はコメントです。dbt ではこれらが SQL 内に混在します。

フィルタはパイプ記法で値を加工します。default, lower, upper, join, replace あたりが頻出です。数値・文字列の扱いでは引用符の有無に注意し、特に識別子(カラム名など)を生成するときは安全性と可読性を意識します。

  • 値の出力: {{ expression }}
  • 制御構文: {% if %}, {% for %}, {% set %}
  • コメント: {# コメント #}
  • よく使うフィルタ: |default('x'), |lower, |upper, |join(', ')
区切り用途
{{ ... }}値を出力{{ var('days', 7) }}
{% ... %}制御構文{% if target.name == 'prod' %} ... {% endif %}
{# ... #}コメント{# build only for daily partition #}

区切りの役割ミニ図

{{ }}出力値を描く{% %}制御流れを作る{# #}コメント無出力区切りの役割: 記法→役割→性質

フィルタと set の例

{% set cols = ['id', 'customer_id', 'order_ts'] %}
select {{ cols | map('lower') | join(', ') }}
from {{ ref('stg_orders') }};

制御構文: if/for と繰り返しで SQL を整える

環境やターゲットに応じて列や条件を切り替えるときに if は有効です。配列やマップを回す for は選択列や CASE 文の量産に向いています。テンプレート化は可読性を落とさない範囲で行い、長いロジックはマクロに切り出します。

ループ内のカンマ区切りや末尾カンマに注意しましょう。join フィルタで安全に区切るか、loop.last を用いて制御します。

  • 環境依存のブランチは target.name を参照
  • ループの区切りは join で安定化
  • 長いロジックはマクロへ切り出し
構文用途試験での着眼点
if/elif/else環境・フラグで分岐target/var による切替
for列や条件の量産join or loop.last で末尾カンマ回避
set中間値の保持複雑化前にマクロ化を検討

for で列リストを組み立てるイメージ

入力['id','name','email']for + join(', ')出力id, name, emailfor + join(', ') で列リストを組み立てる

for と loop.last の例

{% set dims = ['country', 'city', 'zip'] %}
select
  customer_id,
  {% for d in dims %}
  {{ d }}{% if not loop.last %},{% endif %}
  {% endfor %}
from {{ ref('dim_customers') }};

dbt 固有関数: ref, source, var, env_var, config の使い分け

ref はモデル間依存を張りつつ、適切なスキーマ・識別子を解決します。source は外部テーブル参照のために使い、catalog.yml の宣言と一致させます。var は dbt_project.yml やコマンドラインで渡した変数を取得し、env_var は OS 環境変数を参照します。config はマテリアライゼーションやタグなどモデル設定に使います。

Analytics Engineer 試験では、ref と source の区別、var/env_var の優先度、config の適用範囲(モデル内 vs プロジェクト設定)が頻出です。

  • ref は依存解決+スキーマ/識別子の可搬性を担保
  • source は外部テーブル。catalog で宣言必須
  • var は dbt 変数、env_var は OS の環境変数
  • config はモデル単位の設定(materialized, tags など)
関数/構文主用途使える場所試験の注意
ref('model')モデル参照・依存解決モデルSQL/マクロモデル間依存を自動で張る
source('src','table')外部テーブル参照モデルSQL/マクロsources.yml の定義と一致
var('key', default)変数取得モデルSQL/マクロ未定義時の default で安全化
env_var('NAME')環境変数取得モデルSQL/マクロ実行環境に依存
config(...)モデル設定モデルSQL(冒頭)/マクロモデル内 config はそのモデルにのみ適用

ref と source の関係イメージ

source: raw.orderssources.ymlstg_ordersfct_ordersref('fct_orders')source は sources.yml で宣言、下流は ref('fct_orders') で参照

ref, source, var, env_var, config の実例

-- models/fct_orders.sql
{{ config(materialized='table', tags=['finance']) }}

with src as (
  select * from {{ source('raw', 'orders') }}
), stg as (
  select * from {{ ref('stg_orders') }} where order_date >= {{ var('from_date', "'1970-01-01'") }}
)
select * from stg
where {{ 'true' if env_var('ALLOW_ALL', 'false') == 'true' else 'total_amount > 0' }};

マクロの作成・再利用とパッケージ

繰り返し現れる SQL 断片は macros ディレクトリにマクロとして切り出し、呼び出し側で引数を渡します。マクロは Jinja のテンプレートであり、呼び出し時に展開されます。複数プロジェクトで共有するならパッケージ化し、packages.yml から導入します。

run_query はマクロ内で補助的な問い合わせを行いたい場合に限定して使います。モデル本体の SQL 生成を run_query の結果に依存させると、コンパイル・キャッシュ・並列実行で予期せぬ挙動になる可能性があるため、設計としては避けます。

  • マクロは macros/ 配下に .sql ファイルで作成
  • 呼び出しは {{ my_macro(arg=...) }} 形式
  • 共有はパッケージ化し、命名空間で衝突回避
対象配置/定義呼び出し/適用
マクロmacros/*.sql{{ my_macro(arg='x') }}
パッケージpackages.yml で参照{{ package_name.macro_name(...) }}
モデル設定config(materialized='...'){{ config(...) }} or dbt_project.yml

プロジェクト構造の最小例

project/models/stg_orders.sqlfct_orders.sqlmacros/utils.sqlpackages.ymldbt_project.ymlプロジェクト構造の最小例

マクロ定義と呼び出し

-- macros/utils.sql
{% macro coalesce_zero(expr) %}
coalesce({{ expr }}, 0)
{% endmacro %}

-- models/fct_orders.sql(一部)
select {{ coalesce_zero('total_amount') }} as total_amount
from {{ ref('stg_orders') }};

落とし穴と検証: 依存、識別子、安全なテンプレート

ref/source を使わずにハードコードしたスキーマ・テーブル名は、環境差分やリネームで壊れます。必ず ref/source を通し、識別子はアダプタが適切にクオートします。識別子やリテラルの動的生成では、文字列クオートの整合性に注意します。

Jinja のロジックをテストで担保するには、dbt test と unit tests(利用可能な場合)を組み合わせます。テンプレート展開が意図通りかは、dbt compile で生成 SQL を確認するのが最短です。

  • スキーマ・テーブル名のハードコード禁止。ref/source で移植性を担保
  • 文字列と識別子のクオートを混同しない
  • dbt compile で生成 SQL を目視確認
落とし穴症状対策
ハードコード参照環境切替で失敗ref/source を使用
末尾カンマSQL 構文エラーjoin or loop.last で制御
危険な run_query 依存非決定的・遅いメタデータは vars/ソース管理へ

安全な参照と危険な参照

良い: {{ ref('stg_orders') }} -> コンパイル時に解決
悪い: raw_schema.stg_orders -> 環境で破綻

run_query はマクロ内の補助用途に限定

-- macros/get_max_order_date.sql
{% macro get_max_order_date() %}
  {% set res = run_query("select max(order_date) as d from " ~ ref('stg_orders')) %}
  {% if res is not none and res.columns and res.rows %}
    {{ return(res.rows[0][0]) }}
  {% else %}
    {{ return("'1970-01-01'") }}
  {% endif %}
{% endmacro %}

-- 悪手: モデル本体の where に直接 run_query 結果を依存させない

問題で確認

Analytics Engineer

問題 1

Analytics Engineer として、環境ごとに適切なテーブル名を参照しつつ、モデル間の依存関係を正しく張る必要があります。次のうち最も適切な記述はどれか?

  1. from {{ ref('stg_customers') }} を用い、依存と識別子解決を dbt に委ねる
  2. from prod.analytics.stg_customers とフルネームをハードコードする
  3. from {{ var('schema') }}.stg_customers としてスキーマだけ変数化する
  4. from {{ env_var('DBT_SCHEMA') }}.stg_customers と環境変数で参照する

正解: A

ref は依存グラフの構築とアダプタごとの識別子解決を同時に行い、環境差分にも強い。スキーマやテーブルをハードコード、あるいは手作りの変数で連結する方法は移植性や依存解決の点で劣る。

よくある質問

var と env_var はどう使い分けますか?

var は dbt プロジェクトやコマンドラインで管理するテンプレート変数、env_var は実行環境(OS)の値を参照します。再現性の観点から、アプリ挙動に影響する値は原則 var で管理し、資格情報や機密は環境変数(env_var)で渡します。

モデル内と dbt_project.yml の config、どちらが優先されますか?

モデル内の config がそのモデルに対して最終的に適用されます。プロジェクト設定はデフォルト、モデル内は上書きという関係です。

ループで列リストを組み立てるときの安全な書き方は?

join フィルタを使うか、loop.last を用いて末尾カンマを制御します。例: select {{ cols | join(', ') }}。これにより構文エラーを避けられます。

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

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.