not_null は、列に NULL が1件も存在しないことを保証する dbt 標準の汎用テスト。
ソース段階とモデル段階の両方で適用し、早期に欠損を検知するのが実務的にも試験的にも重要。
not_null は、対象列に NULL が1件も無いことを検証する汎用テスト。dbt はテストを「失敗行を返すSELECT」として実行し、0行なら成功、1行以上なら失敗となる。公式ドキュメントの安定仕様で、モデル・ソース・シードに適用できる。
Analytics Engineer 試験では、どの段階で not_null を置くべきか(ソースとステージング/中間・ファクトの両方)、テスト設定(severity, store_failures, where)の理解、そして関連テスト(unique, relationships, accepted_values)との使い分けが狙われやすい。
データ品質チェーンにおける not_null の位置付け
最小構成は、列の tests セクションに not_null を列挙するだけ。重要度の高い列は severity=error、監視開始段階では warn を使い、CIの段階的導入を行う。where で論理削除行などを除外できる。store_failures を有効にすると失敗行が監査用テーブルとして保存され、原因調査が容易になる(保存先のスキーマ名や命名はアダプタに依存)。
ソース段階でも not_null を定義して、上流の欠損混入を早期発見する。ステージング以降では、主キー・外部キー・業務キー列を not_null で締めるのが基本。
YAML例(models と sources での not_null 適用)
version: 2
models:
- name: fct_orders
description: Final fact table for orders
columns:
- name: order_id
description: Primary key
tests:
- unique
- not_null: # クリティカル列はエラー
severity: error
store_failures: true
- name: customer_id
description: Foreign key to dim_customers
tests:
- not_null:
severity: error
where: "is_deleted = false" # 論理削除行を除外する例
- relationships:
to: ref('dim_customers')
field: customer_id
sources:
- name: app
schema: raw_app
tables:
- name: orders_raw
columns:
- name: order_id
tests:
- not_null # 上流欠損の早期検知
- name: created_at
tests:
- not_null: { severity: warn } # 監視しつつ段階導入
dbt test は、対象ノードを選択して実行できる。モデル名指定で、そのモデルに紐づくテストだけを走らせる運用が最も安定。CIではクリティカル列は severity=error でブロック、観測段階は warn でログに残す方針が扱いやすい。
store_failures は、失敗行を調査用に保管する。長期で溜め込みたくない場合は、定期削除ポリシーや専用スキーマを活用する。
空文字とNULLは別物: 多くのDWH(Snowflake, BigQuery, Redshift 等)では '' と NULL は異なる。not_null は空文字を検知しないため、上流で空文字が来る可能性がある場合はステージングで NULLIF(TRIM(col), '') を使って正規化してから not_null を適用する。
JOINでの欠損発生: LEFT JOIN は右側に不一致があると NULL を生む。not_null を守るべき列が JOIN 後に NULL になる場合、JOIN戦略の見直し(INNER JOIN化、事前フィルタ、COALESCEの適用)が必要。
型変換・派生列: CAST 失敗や条件分岐により意図せず NULL を生むことがある。派生直後に COALESCE でデフォルト値を与えるか、期待値の範囲を accepted_values と併用して品質を補強する。
ソース段階での not_null は早期検知、ステージング・コア段階の not_null は契約保証の役割を担う。特に主キー・外部キー・ビジネスキーは、not_null と unique/relationships を組み合わせて恒常監視する。
CI/CD では、クリティカル列の not_null 失敗をデプロイブロックの条件にする。失敗行は store_failures によって監査スキーマへ保存し、失敗検出から復旧までのSLAをドキュメント化する。
not_null は「存在」を保証するが、完全性は他テストとの組み合わせで担保する。代表的なテストとの比較を押さえておくと、試験の選択問題にも強くなる。
| テスト | 目的 | 代表的な失敗例 | 運用のコツ |
|---|---|---|---|
| not_null | NULLの排除(存在保証) | JOIN不一致でNULL化、空文字をNULL化していない | ステージングでNULL正規化→not_null適用 |
| unique | 重複の排除(一意性) | 同じIDが複数行 | not_nullと併用して主キー保証 |
| relationships | 参照整合性(外部キー) | 親テーブルに存在しないID | 親子両方でnot_nullを付与し、孤児検出 |
| accepted_values | コード体系の遵守 | 予定外のカテゴリ値 | NULLを別扱いにしたい場合は併用順序に注意 |
Analytics Engineer
問題 1
次の要件を同時に満たす最も適切な設定はどれか。要件: 1) fct_orders.order_id は必須であるためCIで失敗したらデプロイを止めたい、2) is_deleted=true の行は検証対象から除外したい、3) 失敗行は調査のため保存したい。
正解: A
CIでブロックするには severity=error、除外条件は is_deleted=false、失敗行の保存は store_failures=true。not_null が要件に最も合致する。
not_null は空文字 '' を検知しますか?
多くのDWHで '' は NULL ではありません。not_null は NULL のみを検知します。空文字対策はステージングで NULLIF(TRIM(col), '') による正規化を併用してください。
大規模テーブルで not_null の実行時間が長いです。短縮できますか?
where で対象範囲を絞る、パーティション列に条件を付ける、重要列のみを先に実行する(タグで選択)などが実務的です。全件検証はバッチで定期実施すると安全です。
ソースとモデルのどちらで not_null を定義すべきですか?
両方です。ソースで上流欠損を早期検知し、モデル側では主キー・外部キー・ビジネスキーなど契約上必須の列を再度検証して品質を二重化します。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
dbt Model の基礎: SQL で定義する変換の最小単位
Analytics Engineer 向けに、dbt Model の定義、マテリアライゼーション、依存関係、インクリメン...
dbt Analytics Engineer 試験ガイド: 出題範囲・配点・申込の実務視点
dbt Analytics Engineer 認定の出題範囲、配点の考え方、申込から受験までの流れを、公式ドキュメントの...
dbt Cloud と dbt Core の違いと選び方:Analytics Engineer 試験に効く要点
dbt Cloud と dbt Core の機能差を、実務と資格対策の両面から整理。スケジューリング、IDE、RBAC、...
dbt プロジェクト構造ガイド: models / seeds / macros の実務レイアウト
Analytics Engineer 向けに、dbt プロジェクトのディレクトリ構造と命名規約、dbt_project....
dbt_project.yml の読み方:主要設定と命名を最短で掴む
dbt_project.yml の必須キー、命名解決(database.schema.identifier)、設定優先度...