Teradataで追加カラムの無影響確認|Antiselectで『選ばない列』を指定する

この記事で分かること

  • Teradataで 既存テーブルへのカラム追加 が多い理由と、そのときのテストの考え方
  • 「追加カラムの正しさ」と「既存カラムへの無影響」は別確認であること
  • 無影響確認で全カラム列挙+MINUS すると、列が多いほどSQLが読みにくくミスしやすいこと
  • 選ばない列だけを指定できる Antiselect の使い方

結論(先に要点)

ユーザー要望で、既存テーブルにカラムを足す開発は Teradata 現場では意外と多いです。
そのときテストはだいたい次の2層になります。

  1. 追加カラムが仕様どおりか
  2. 既存カラムに変な影響が出ていないか(無影響確認)

無影響確認の定石は、「追加カラムを除いた列だけ」を新旧で突き合わせ、差分がゼロならよし、です。
列が多いと「残す列を全部書く」SQLが長くなり、視認性が落ちて間違いも増えます。

こうした場合は逆に、SELECTしない列(追加した列)だけを選ぶ方が分かりやすいです。
Teradataではそのためのテーブル演算子として Antiselect があります。

※ 本稿のデータベース名・テーブル名・列名は、すべて説明用の仮名です。実案件の識別子はそのまま載せていません。
※ Antiselect は環境によって利用可否が異なります(Vantage の In-Database Analytic Functions 系)。使えない場合は、後述の代替も検討してください。

よくある開発:既存テーブルへのカラム追加

新規テーブルをゼロから作るより、

  • 既存の業務テーブルに項目を足す
  • 下流が同じテーブル名のまま追加列だけ使う

といった改修が続くことがあります。ALTER でカラムを足す、または同等の定義変更です。

テストでは次がセットになります。

確認 目的
追加カラムの内容 仕様(計算式・NULL・コード値など)に合っているか
既存カラムの無影響 今回の修正で、もともとあった列の値が変わっていないか

追加列だけ見て「仕様OK」でも、結合や更新の副作用で既存列が動いていると事故になります。だから無影響確認はふつうに入ります。

無影響確認の定石:追加列を除いて MINUS

イメージは次です。

[改修前のテーブル] の「既存列だけ」
        MINUS
[改修後のテーブル] の「既存列だけ」
        → 0行なら、既存列は一致(無影響とみなす)

Teradata では集合差に MINUS(または EXCEPT)を使います。
両側のSELECTは、同じ列・同じ型・同じ順である必要があります。

素朴な書き方(列を全部列挙)

追加列が new_flag だけなら、理屈の上ではこう書けます。

-- 仮名の例。列が多いとこの列挙が破綻しやすい
SELECT
  customer_id,
  order_id,
  order_date,
  amount
  -- …既存列が50個あると、ここに延々と続く…
FROM db_before.sales_detail

MINUS

SELECT
  customer_id,
  order_id,
  order_date,
  amount
  -- …同じ列をまた全部…
FROM db_after.sales_detail
;

問題は次です。

  • カラム数が多いとSQLが極端に長い
  • 1列でも抜け・順違いがあると、差分が出たり構文エラーになったりする
  • 「今回触っていない列」なのに、列挙ミスで偽の差分や偽のOKになる

つまり、残す側を全部書くのは、無影響確認の本質に対してコストが高いです。

発想の転換:選ばない列だけ指定する

無影響確認で本当に除外したいのは、だいたい 今回追加したカラムだけ(または意図的に比較対象外にした列)です。
なら SQL は「全部から、これとこれを除く」と書いた方が短いし、意図が読めます。

そのための仕組みが Antiselect です。
名前のとおり、anti-select=選ばない、の発想です。

Antiselect の使い方

基本構文

公式ドキュメント上の骨格は次です。

SELECT *
FROM Antiselect (
  ON { テーブル | ビュー | (サブクエリ) }
  USING
    Exclude ( { '除外する列名' | 列範囲 } [,...] )
) AS alias_name
;
  • ON … 入力(テーブル/ビュー/クエリ)
  • Exclude出力から外す列(ここに追加カラム名を書く)
  • 出力は「入力の全列から、Exclude した列を除いたもの」

追加カラム1本を除外する例

改修後テーブルから、追加列 new_flag だけを除いて既存列セットを得ます。

SELECT *
FROM Antiselect (
  ON db_after.sales_detail
  USING
    Exclude ('new_flag')
) AS a
;

改修前テーブルに new_flag が無いなら、改修前はそのまま全列、改修後だけ Antiselect、という組み合わせになります(列構成が揃うようにする)。

無影響確認への組み込み例

-- 改修前(追加列なし): 全列が「既存列」
SELECT *
FROM db_before.sales_detail

MINUS

-- 改修後: 追加列だけ除外して、既存列セットを作る
SELECT *
FROM Antiselect (
  ON db_after.sales_detail
  USING
    Exclude ('new_flag')
) AS after_existing
;

結果が 0行 なら、追加列を除いた範囲では差分なし、と読めます。
(必要なら逆向きの MINUS も行い、片側だけの行が無いかを見ます。)

追加列が複数なら、Exclude に並べます。

Exclude ('new_flag', 'new_score', 'new_comment')

列範囲の指定(任意)

Antiselect は、列名のほか、範囲指定もサポートします(ドキュメント上の例)。

  • 'start_col:end_col' … 名前の範囲
  • '[0:4]' … 先頭からインデックスで範囲(先頭は0)

無影響確認では、通常は 追加した列名を明示する方が意図がはっきりします。範囲指定は、列が規則的に並んでいるとき向けです。

実務での進め方(判断基準)

  1. 追加カラムの仕様テスト(値・NULL・件数など)を別途行う
  2. 無影響確認では、比較対象外の列(追加列)を決める
  3. 既存列が多ければ Antiselect で除外し、MINUS で突き合わせる
  4. 差分が出たら、列挙ミスではなく中身差分の可能性として切り分ける

BigQuery側の「結果が同じか」検証(ハッシュ比較)と同じく、ゴールは差分ゼロの確認です。手段が「全列列挙」か「除外指定」かの違いです。

失敗例と回避策

  • 失敗: 既存列を50個手書きし、1列抜けて偽の差分/偽の一致
    回避: Antiselect で追加列だけ Exclude
  • 失敗: Exclude に追加列を書き忘れ、比較に新列が混ざる
    回避: 「今回追加した列一覧」をチケットとSQLのコメントに残す
  • 失敗: 改修前と改修後でキー粒度が違い、MINUS が大量差分になる
    回避: 無影響は「同じキー空間」が前提。件数が先にズレていないか見る

Antiselect が使えないとき

環境に Analytic Functions / Antiselect が無い場合は、次の代替になります。

  • ビューで「既存列だけ」を定義し、MINUS の両側からそのビューを使う
  • 生成SQL(情報スキーマから列名を組み立て、追加列を除く)で列挙を自動化する
  • 比較用に「既存列だけのスナップショット表」を一度作る

どれも「選ばない列を中心に考える」点は同じです。

まとめ

  • Teradataでは既存テーブルへのカラム追加が多く、追加列の仕様確認+既存列の無影響確認がセット
  • 無影響は、追加列を除いたセット同士の MINUS が定石
  • 列が多いと全列列挙は読みにくくミスやすい → 選ばない列を指定する方がよい
  • そのための演算子が AntiselectExclude に外す列を書く)
  • 利用可否は環境依存。無ければビューや列名生成で同じ発想を再現する

次に読む

タイトルとURLをコピーしました