この記事で分かること
- Teradataで 既存テーブルへのカラム追加 が多い理由と、そのときのテストの考え方
- 「追加カラムの正しさ」と「既存カラムへの無影響」は別確認であること
- 無影響確認で全カラム列挙+
MINUSすると、列が多いほどSQLが読みにくくミスしやすいこと - 選ばない列だけを指定できる Antiselect の使い方
結論(先に要点)
ユーザー要望で、既存テーブルにカラムを足す開発は Teradata 現場では意外と多いです。
そのときテストはだいたい次の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)
無影響確認では、通常は 追加した列名を明示する方が意図がはっきりします。範囲指定は、列が規則的に並んでいるとき向けです。
実務での進め方(判断基準)
- 追加カラムの仕様テスト(値・NULL・件数など)を別途行う
- 無影響確認では、比較対象外の列(追加列)を決める
- 既存列が多ければ Antiselect で除外し、
MINUSで突き合わせる - 差分が出たら、列挙ミスではなく中身差分の可能性として切り分ける
BigQuery側の「結果が同じか」検証(ハッシュ比較)と同じく、ゴールは差分ゼロの確認です。手段が「全列列挙」か「除外指定」かの違いです。
失敗例と回避策
- 失敗: 既存列を50個手書きし、1列抜けて偽の差分/偽の一致
回避: Antiselect で追加列だけ Exclude - 失敗: Exclude に追加列を書き忘れ、比較に新列が混ざる
回避: 「今回追加した列一覧」をチケットとSQLのコメントに残す - 失敗: 改修前と改修後でキー粒度が違い、MINUS が大量差分になる
回避: 無影響は「同じキー空間」が前提。件数が先にズレていないか見る
Antiselect が使えないとき
環境に Analytic Functions / Antiselect が無い場合は、次の代替になります。
- ビューで「既存列だけ」を定義し、MINUS の両側からそのビューを使う
- 生成SQL(情報スキーマから列名を組み立て、追加列を除く)で列挙を自動化する
- 比較用に「既存列だけのスナップショット表」を一度作る
どれも「選ばない列を中心に考える」点は同じです。
まとめ
- Teradataでは既存テーブルへのカラム追加が多く、追加列の仕様確認+既存列の無影響確認がセット
- 無影響は、追加列を除いたセット同士の
MINUSが定石 - 列が多いと全列列挙は読みにくくミスやすい → 選ばない列を指定する方がよい
- そのための演算子が Antiselect(
Excludeに外す列を書く) - 利用可否は環境依存。無ければビューや列名生成で同じ発想を再現する
