Dataform の updatePartitionFilter で複数の動的日付フィルタを指定する
こんにちは、クラウドエース株式会社第四開発部の渡辺です。
Dataform で incremental テーブルを運用していると、「特定の日付範囲だけ再計算したい」という場面が出てきます。
本記事では、updatePartitionFilter に 開始日・終了日のような複数の動的条件 を載せる方法を紹介します。
概要
incremental テーブルの更新対象パーティションは、updatePartitionFilter で絞り込めます。
期間を実行時に変えたい場合は dataform.projectConfig.vars を使い、条件が複数ある場合は JavaScript の式で 1 本の SQL 条件文字列 を組み立てます。
updatePartitionFilter:
(!!dataform.projectConfig.vars.start_date && !!dataform.projectConfig.vars.end_date)
? `date >= DATE('${dataform.projectConfig.vars.start_date}') AND T.date <= DATE('${dataform.projectConfig.vars.end_date}')`
: `date >= DATE_SUB(CURRENT_DATE('Asia/Tokyo'), INTERVAL 7 DAY)`
はじめに
BigQuery 上のテーブルを Dataform で incremental に更新する場合、毎回すべてのパーティションを書き換えるのではなく、対象期間のパーティションだけ を更新したいことがあります。
その絞り込みに使うのが updatePartitionFilter です。
固定の日付文字列でも動きますが、次のような要件になると途端に扱いづらくなります。
- 実行のたびに開始日・終了日を変えたい
- 開始日と終了日の両方で範囲を指定したい
本記事では、静的な書き方から始め、vars による動的指定、そして複数条件を 1 つのフィルタに載せる書き方まで順に説明します。
incremental と updatePartitionFilter
Dataform の incremental テーブルでは、差分更新の対象をパーティション単位で制御できます。
updatePartitionFilter には、更新対象とするパーティションを表す SQL の条件式(文字列) を渡します。
イメージとしては、次のような条件で「どの日付のパーティションを更新するか」を指定します。
date >= DATE('2026-07-01')
この条件に合うパーティションだけが、今回の実行で更新対象になります。
静的な日付フィルタの例
まずは固定日付での指定です。
config {
type: "incremental",
uniqueKey: ["id"],
bigquery: {
partitionBy: "date",
updatePartitionFilter: `date >= DATE('2026-07-01')`
}
}
この書き方は単純で分かりやすい反面、期間を変えるたびに定義を修正する必要があります。
「昨日から今日まで」「先月の全期間」など、実行ごとに期間が変わる運用では向きません。
動的にしたい・条件を複数にしたい
実務では、次の 2 つが同時に求められることが多いです。
- 動的: 実行時に期間を渡したい
- 複数条件: 開始日以上かつ終了日以下、のように範囲で絞りたい
updatePartitionFilter に渡せるのは最終的には 1 つの条件文字列 です。
そのため、開始日と終了日を別々のオプションとして渡すのではなく、Dataform 側の JavaScript で文字列を組み立て、AND でつなぐ必要があります。
projectConfig.vars で日付を渡す
実行時の値は dataform.projectConfig.vars 経由で参照できます。
たとえば start_date と end_date を vars として渡すと、定義側では次のように読めます。
dataform.projectConfig.vars.start_date
dataform.projectConfig.vars.end_date
vars の渡し方の例です(CLI の場合)。
dataform run --vars=start_date=2026-07-01,end_date=2026-07-31
dataform.json の vars にデフォルト値を置いておく運用もあります。
どちらにしても、テーブル定義からは dataform.projectConfig.vars.* として参照する点が共通です。
複数条件を updatePartitionFilter に載せる
ここが本題です。
vars が両方そろっているときだけ範囲指定の文字列を作り、そうでないときはフォールバックの条件を使う、という形にすると扱いやすいです。
このコードには 2 種類の日付フィルタが登場します。
-
updatePartitionFilter(config 内):MERGE 文の ON 句に展開され、今回の実行で書き換えるパーティションの範囲を指定します。 -
dateFilter(js ブロック内):SELECT の WHERE 句に展開され、ソーステーブルから読み込む行の範囲を指定します。
2 つを同じ期間で揃えることで、書き換え対象のパーティションだけを絞り込みつつ、無駄なデータスキャンも防げます。
SQLX
config {
type: "incremental",
schema: dataform.projectConfig.defaultDataset,
name: "target_table",
tags: ["target_table"],
uniqueKey: ["id"],
bigquery: {
partitionBy: "date",
updatePartitionFilter:
(!!dataform.projectConfig.vars.start_date && !!dataform.projectConfig.vars.end_date)
? `date >= DATE('${dataform.projectConfig.vars.start_date}') AND T.date <= DATE('${dataform.projectConfig.vars.end_date}')`
: `date >= DATE_SUB(CURRENT_DATE('Asia/Tokyo'), INTERVAL 7 DAY)`
}
}
/* 実行時引数(vars)が存在する場合はその範囲、未指定時は「直近 7 日間」をフィルタ条件として生成 */
js {
const start_val = dataform.projectConfig.vars.start_date ? `'${dataform.projectConfig.vars.start_date}'` : "NULL";
const end_val = dataform.projectConfig.vars.end_date ? `'${dataform.projectConfig.vars.end_date}'` : "NULL";
var dateFilter = `date >= COALESCE(DATE(${start_val}), DATE_SUB(CURRENT_DATE('Asia/Tokyo'), INTERVAL 7 DAY))
AND date <= COALESCE(DATE(${end_val}), CURRENT_DATE('Asia/Tokyo'))`;
}
SELECT
id,
date,
value
FROM ${ref("source_table")}
WHERE ${dateFilter}
補足: updatePartitionFilter と dateFilter では、変数が片方だけ渡された場合の挙動が異なります。
-
updatePartitionFilterは両変数が揃っていないとフォールバック条件に切り替わります -
dateFilterは各変数を独立してCOALESCEするため、start_dateだけ渡すと終了日には当日が使われます
片方のみの指定を運用上禁止する場合は、dateFilter 側も三項演算子に統一すると一貫性が高くなります。
workflow_settings.yaml
# Dataform コアのバージョン設定
dataformCoreVersion: 3.0.0
# BigQuery のデフォルト接続設定
defaultProject: "your-gcp-project"
defaultDataset: "test_dataset"
defaultLocation: "asia-northeast1"
defaultAssertionDataset: "dataform_assertions"
# vars のデフォルト値(CLI や API で上書きされなかった場合に使われます)
vars:
start_date: "2026-07-01"
end_date: "2026-07-15"
ポイントを分解すると次のとおりです。
1. vars の存在チェック
!!dataform.projectConfig.vars.start_date && !!dataform.projectConfig.vars.end_date
start_date と end_date の両方が渡されているかを確認しています。
片方だけ渡された状態で不完全な SQL を生成しないためのガードです。
2. 三項演算子で条件文字列を切り替える
条件 ? `範囲指定の SQL` : `フォールバックの SQL`
updatePartitionFilter には常に有効な条件文字列を渡したいので、未設定時の挙動も明示します。
上の例では「直近 7 日」をデフォルトにしていますが、運用に合わせて変えてください。
3. テンプレートリテラルで SQL を組み立てる
`date >= DATE('${dataform.projectConfig.vars.start_date}') AND T.date <= DATE('${dataform.projectConfig.vars.end_date}')`
vars の値を SQL リテラルに埋め込みます。
複数条件は、ここで SQL の AND としてつなぎます。
2 つ目以降の条件では、パーティション カラムに T. を明示する点が重要です(理由は後述の注意点を参照)。
実装時の注意点
1. 未設定時の挙動を決めておく
三項演算子の false 側を省略したり、空文字を返したりすると、意図しない全件更新や実行エラーにつながることがあります。
「vars 必須にする」「未指定時は直近 N 日」「未指定時は前日のみ」など、運用ルールを先に決めておくのが安全です。
2. 2 つ目以降の条件には T. を付ける
updatePartitionFilter に複数条件を書く場合、Dataform は 1 つ目の条件 に対してテーブルエイリアス T. を自動で補完します。
一方で 2 つ目以降の条件 には補完されません。
そのため、次のようにどちらも date と書くと、生成された MERGE 文の ON 句で 2 つ目の date が曖昧参照になり、実行時エラーになります。
// NG 例: 2 つ目に T. がなくエラーになる
`date >= DATE('...') AND date <= DATE('...')`
// OK 例: 2 つ目以降は T. を明示する
`date >= DATE('...') AND T.date <= DATE('...')`
実際に NG 例で実行すると、次のようなエラーになります。
Query error: Column name date is ambiguous at [****:20:52]
生成 SQL を見ると、1 つ目の条件だけ T.date に補完され、2 つ目は date のまま残っていることが分かります(緑枠が補完済み、赤枠が未補完)。

一方、2 つ目以降にも T. を明示すると、両方の条件が T.date として解決され、正常に実行できます。

T(ターゲット)と S(ソース)の両方に date カラムがあるため、エイリアスなしの date はどちらを指すか判別できず失敗します。
複数条件を AND でつなぐときは、2 つ目以降のパーティションカラムに T. を付けるのを忘れないでください。
3. 日付フォーマットと型を合わせる
vars に渡す値は、BigQuery 側で DATE('...') として解釈できる形式(例: YYYY-MM-DD)に揃えます。
パーティションカラムが TIMESTAMP の場合は、DATE() ではなく TIMESTAMP() や DATE(timestamp_col) など、型に合わせた式にしてください。
まとめ
- incremental テーブルの更新範囲は
updatePartitionFilterで絞れる - 実行ごとに期間を変えたいときは
dataform.projectConfig.varsを使う - 開始日・終了日のように条件が複数ある場合は、JavaScript で 1 本の SQL 条件文字列 を組み立て、
ANDでつなぐ - 2 つ目以降の条件ではパーティションカラムに
T.を明示する - vars 未設定時のフォールバックもセットで設計する
updatePartitionFilter 自体は単純な設定ですが、「動的」かつ「複数条件」になると、SQL 文字列をどう組み立てるかがポイントになります。
Discussion