dbt

dbt unique テスト: 一意性保証の基本

2026-04-19
NicheeLab編集部

unique テストは、主キー候補やビジネスキーの重複を即座に検知するための最小単位の品質ゲートです。

本稿では、定義・実行・失敗時の対処・CI 連携・ウェアハウス差分・試験で問われやすい要点を、公式ドキュメントの挙動に沿って解説します。

unique テストの基本と失敗条件

dbt の generic テスト unique は、指定列の各値がテーブル内で一意であることを検証します。内部的には対象列で GROUP BY し、同じ値が2件以上あれば失敗と判定します。NULL も1つの値として集約されるため、NULL が2件以上あると unique は失敗します。したがって、主キー相当の厳密性を求める場合は unique と not_null を組み合わせます。

テストは通常、モデルの YAML プロパティファイルに宣言します。dbt test 実行時、dbt は該当モデルに対して検査用の SQL を生成し、行が返れば失敗、0件なら成功という単純明快なルールで評価します。

  • 対象: 単一列の一意性
  • 失敗条件: 同一値が2件以上、または NULL が2件以上存在
  • 主キー相当: unique + not_null の併用が必須
  • 評価ロジック: 検査クエリの結果が1行以上なら失敗
テスト目的よくある失敗例併用推奨
unique重複検出(同値が2件以上)JOIN の多重化で fan-outnot_null
not_nullNULL の排除欠損許容列に誤適用unique
relationships参照整合性(外部キー的)参照先未投入・遅延到着unique + not_null(参照元キー側)

ETL/ELT とテストの配置(概念図)

sourcesstagingmarts/fcttestsunique / not_null / relationships

YAML による unique と not_null の併用例

version: 2
models:
  - name: fct_orders
    description: 受注のファクトテーブル(order_id は主キー相当)
    columns:
      - name: order_id
        tests:
          - unique
          - not_null
      - name: customer_id
        tests:
          - relationships:
              to: ref('dim_customers')
              field: customer_id

セットアップと実行方法

プロパティは models ディレクトリ配下の YML(例: models/schema.yml)に配置します。dbt test は選択子で対象を絞れます。変更の影響範囲のみ検査したい場合、state:modified といったステートフル選択を CI と組み合わせるのが定石です。

unique 失敗時は即座に修正できるよう、モデル名や列名をエラーに出す命名・コメント整備が有効です。

  • 基本: dbt test -s <model or selector>
  • 列単位: dbt test -s model_name.column_name
  • 変更のみ: dbt test -s state:modified+(CI 利用が多い)
  • すべて: dbt test(全モデル・全カラムの宣言済みテスト)
コマンドスコープ用途
dbt test -s fct_ordersモデル単位対象モデルのみ検査
dbt test -s fct_orders.order_id列単位問題列のスポット検査
dbt test -s state:modified+変更+依存先PR での差分検査

選択子によるテスト対象の絞り込み(概念)

all modelsstate:modified変更state:modified+変更とその下流(依存先)

CLI 実行例(ローカル / CI 共通)

# 単一モデル
$ dbt test -s fct_orders

# 列を直接指定
$ dbt test -s fct_orders.order_id

# 変更の下流まで
$ dbt test -s state:modified+

失敗時の原因究明と重複除去パターン

unique 失敗の多くは、JOIN による fan-out(多重化)、重複行の取り込み、遅延到着データの再投入が原因です。まずは失敗テストが生成した検査 SQL を dbt debug ではなく、コンパイル結果(target/compiled)やログから確認し、GROUP BY 対象の値ごとの件数を観察します。

重複除去は、ウィンドウ関数で最新レコードを1件だけ残すのが定番です。増分モデルでは unique_key 設定と合わせて、重複そのものを作らない設計(ソース段階の正規化やキー定義)も重要です。

  • 原因特定は検査 SQL を見る(count と group by)
  • JOIN ファンアウトは集約または DISTINCT で抑制
  • 最新判定は row_number() over(partition by ... order by updated_at desc)
  • 増分は unique_key と upsert を組み合わせて重複を防止
症状観測ポイント対処
JOIN 後に件数が倍増結合キーの一対多事前集約 or DISTINCT or 代表行選択
取り込みで同一レコードが再出現同一キー・異なる更新時刻row_number で最新のみ採用
NULL の多発NULL が2件以上not_null の追加と上流修正

重複除去の流れ(例)

rawstagingdedupedrow_numberで代表行選択marts (unique OK)

重複除去の SQL 例(最新1件を採用)

with src as (
  select * from {{ ref('stg_orders') }}
), ranked as (
  select
    *,
    row_number() over(
      partition by order_id
      order by updated_at desc
    ) as rn
  from src
)
select
  -- 必要な列
  order_id, customer_id, amount, updated_at
from ranked
where rn = 1

CI/CD と品質ゲートとしての扱い

unique は本番反映の可否を左右するゲートとして運用するのが一般的です。失敗時にパイプラインを中断したい列には severity: error、許容したい状況(移行期間など)には severity: warn を使い分けます。severity の既定は error です。

変更差分のみ検査することで、CI の所要時間を抑えつつ品質を担保できます。テストの命名・説明文を充実させると、失敗時の判断が早くなります。

  • 厳格なキー列は severity: error
  • 移行や段階的導入では severity: warn
  • state 選択で高速化
  • PR で dbt run 後に dbt test を実行しゲート化
severityパイプラインの挙動主な用途
error(既定)失敗で中断主キー・参照キー・課金影響の大きい集計
warn警告ログのみで続行移行中の暫定品質・段階的是正

CI での実行順序(概念)

checkoutdepsbuilddbt runtestsdbt testgateunique 失敗で stop

YAML で severity を列ごとに設定

version: 2
models:
  - name: fct_orders
    columns:
      - name: order_id
        tests:
          - unique:
              config:
                severity: error
          - not_null
      - name: legacy_order_code
        description: 移行期間中は重複の可能性あり
        tests:
          - unique:
              config:
                severity: warn

ウェアハウスごとの注意点(NULL・大文字小文字・照合)

dbt の unique は生成 SQL の GROUP BY/HAVING に依存します。NULL は2件以上で失敗、1件だけなら成功という挙動は各主要 DWH で一貫しています。一方で、文字列比較の大文字小文字や照合順序(collation)により、重複と見なすかが変わる場合があります。

ケース非依存で一意性を保証したい場合は、正規化(lower/upper)した派生列に対して unique を当てる、あるいはカスタム generic テストを実装します。

  • NULL は2件以上で unique 失敗(主要 DWH 共通)
  • 大小文字・照合は DWH 設定に依存
  • 必要に応じて正規化列で検査
  • 複合ユニークはカスタムテストやパッケージ活用
DWHケース感度の既定対策例
SnowflakeBINARY(一般に大小区別)lower() 列を検査
BigQuery大小区別(既定)正規化列や collation 指定(一部関数依存)
Databricks SQLSpark SQL 準拠(大小区別が基本)正規化列で検査

正規化して検査する流れ

raw_valuenormalized_valuelower()OK/NGunique test

カスタム generic テスト(ケース非依存の一意性)

{% macro test_unique_lower(model, column_name) %}
with base as (
  select lower({{ column_name }}) as val from {{ model }}
), agg as (
  select val, count(*) as n from base group by 1 having count(*) > 1
)
select * from agg
{% endmacro %}

# 呼び出し(YAML)
# tests:
#   - unique_lower:
#       column_name: user_email

試験対策チェックポイント(Analytics Engineer)

試験では、unique テストの意味、NULL との関係、not_null との組み合わせ、選択子によるテスト実行の知識が頻出です。また、増分モデルの unique_key とテストの役割の違い(実行時のマージ鍵 vs 品質検査)は区別して覚えておきましょう。

関係性テストや受け入れ値テストとの使い分け、警告とエラーの運用判断も問われやすい領域です。

  • primary key 相当 = unique + not_null
  • NULL は1件なら OK、2件以上で NG(unique の性質)
  • dbt test -s state:modified+ の意味を把握
  • unique_key は増分アップサート用、テストではない
トピック重要度覚えるフレーズ
unique と not_null の関係主キー=重複なしかつ NULL なし
選択子(state:modified+)差分と下流をテスト
severity の使い分けerror でゲート、warn で観測

知識整理のイメージ

Schema Testsuniquenot_nullrelationshipsaccepted_values

チートシート(YAML 抜粋)

version: 2
models:
  - name: some_model
    columns:
      - name: business_key
        tests:
          - unique
          - not_null
          - relationships:
              to: ref('dim_ref')
              field: business_key

問題で確認

Analytics Engineer

問題 1

dbt の generic テスト unique の挙動として正しいものはどれか。主キー相当の厳密性を担保したい場合の推奨も含めて選べ。

  1. 同一値が2件以上で失敗し、NULL が2件以上あっても失敗する。主キー相当には not_null と併用する。
  2. 同一値が2件以上で失敗するが、NULL は何件あっても無視される。主キー相当には unique 単独で十分である。
  3. 同一値が3件以上で初めて失敗し、NULL は常に許容されない。
  4. unique は relationships の糖衣構文であり、参照整合性のみを検査する。

正解: A

unique は対象列で GROUP BY/HAVING を行い、同一値が2件以上(NULL も1つの値として集約されるため2件以上の NULL を含む)で失敗します。主キー相当の厳密性には unique と not_null の併用が必要です。

よくある質問

unique と not_null はどちらを先に入れるべきか?

順序は任意ですが、主キー相当の列には両方を必ず定義します。unique だけでは NULL が1件だけ存在しても失敗しないため、NULL を禁止する not_null を合わせて担保します。

複合ユニーク(複数列の組合せ)はどう検査する?

公式の unique は単一列向けです。複合ユニークはカスタム generic テストを実装するか、コミュニティパッケージ(例: dbt_utils の unique_combination_of_columns)を利用します。

incremental モデルの unique_key 設定と unique テストの違いは?

unique_key は増分実行時のマージ鍵(upsert キー)で、重複を発生させにくくする実行時の挙動制御です。unique テストは生成物の一意性を検査する品質チェックであり、両方を併用するのが実務では一般的です。

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

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の記事一覧 (100件)
© 2026 NicheeLab All rights reserved.