SAS Base Programming · 15-20%

エラーハンドリング

構文エラーを直すだけでなく、実行はできたが結果が違うロジックエラーをログと検算で見抜く領域。

試験対策ハブ · 詳細項目

Mindset

ログは最後ではなく、処理の一部として読む

SAS では、エラーが出なくても結果が間違っていることがあります。ERROR、WARNING、NOTE をすべて得点源として扱います。

ERROR

  • 構文として成立しない、ファイルがない、BY 変数が不正など。
  • 最初の ERROR を優先して直す。

WARNING

  • 処理は続くが、結果が怪しい状態。
  • 意図しない型変換、出力上書き、文字値の切り詰めなどに注意。

NOTE

  • 自動変換、未初期化変数、欠損値生成など重要なヒントを含む。
  • 試験では NOTE を読めるかが差になります。

Log Reading

ログは上から順に、最初の原因を探す

1 つの構文ミスが、後続の行に複数の ERROR を連鎖させることがあります。ログを読むときは、最後のメッセージではなく、最初に異常が出た位置を優先します。

1. ERROR の最初を見る

セミコロン欠落、引用符不一致、スペルミス、無効オプションなど、構文として実行できない原因を先に直す。

2. WARNING を読む

処理は続いても、上書き、切り詰め、形式不一致などで結果が崩れていないか確認する。

3. NOTE を捨てない

自動変換、未初期化変数、欠損値生成、入力行数や出力行数は、ロジックエラーの手がかりになる。

4. 件数で検算する

ログの obs 数、PROC FREQPROC MEANSPROC PRINT(obs=) で、問題文の条件どおりに行が残っているか見る。

PUTLOG

ロジックエラーを PUTLOG で追跡する

PUTLOG は DATA ステップ中の値をログに出します。全件出すと読めないので、条件付きで絞るのが実務でも試験でも有効です。

構文解説: 特定ケースだけログに出す

  • by customer_id; は顧客ごとのグループ境界を使うための宣言。
  • first.customer_id で累計を初期化し、SUM ステートメントで加算する。
  • if customer_id = "C001" then do; は、確認したい ID だけにログ出力を絞る。
  • putlog "DEBUG: " _n_= ...; は、反復回数と変数名つきの値をログに出す。
data work.debug_total;
  set work.orders_by_customer;
  by customer_id;
  if first.customer_id then total_amount = 0;
  total_amount + amount;

  if customer_id = "C001" then do;
    putlog "DEBUG: " _n_= customer_id= order_date= amount= total_amount=;
  end;

  if last.customer_id then output;
run;
覚える形

putlog _all_; は全変数を出せます。原因が見えないときの最終手段として便利ですが、ログが大きくなるため条件付きで使います。

自動変数

_N_ は DATA ステップの反復回数、_ERROR_ はその反復でエラーが発生したかを示す一時変数です。ログ確認や条件付きデバッグで役立ちます。

Debug Patterns

PUTLOG は「いつ」「どの行で」壊れたかを絞る

ロジックエラーは、全行を眺めても見つかりません。疑わしい条件、特定 ID、グループの先頭・末尾など、原因が出そうな場面だけログに出します。

構文解説: 境界と異常値を分けて見る

  • first.customer_id or last.customer_id は、グループの先頭・末尾だけをログに出す条件。
  • first.customer_id= のように末尾に = を付けると、変数名と値を一緒に出せる。
  • missing(amount) は欠損値を見つける条件。
  • 境界ログと異常値ログを分けると、累計ミスと入力値ミスを切り分けやすい。
data work.debug_group;
  set work.orders_by_customer;
  by customer_id;
  if first.customer_id then total_amount = 0;
  total_amount + amount;

  if first.customer_id or last.customer_id then
    putlog "BOUNDARY: " _n_= customer_id= first.customer_id= last.customer_id= total_amount=;

  if missing(amount) then
    putlog "MISSING AMOUNT: " _n_= customer_id= order_date= amount=;

  if last.customer_id then output;
run;

境界を見る

  • first. / last. が期待どおりの単位で立っているか確認する。
  • BY 変数を増やしたときは、初期化する単位を見直す。

異常値を見る

  • 欠損、負の金額、想定外カテゴリなど、問題文の条件から外れる行だけ出す。
  • ログが大きくなりすぎないよう、条件付きで出力する。

Syntax

構文エラーの典型パターン

よくある

セミコロン欠落

次の行まで 1 つのステートメントとして読まれ、後続に連鎖エラーが出る。

よくある

引用符不一致

文字列が閉じられず、以降のコードが文字列扱いになる。

よくある

キーワードのスペルミス

formtlegnth など。SAS は補正しない。

よくある

無効なオプション

PROC やステートメントごとに使えるオプションが違う。

Common Notes

NOTE を読めると、ロジックエラーに早く気づける

NOTE は「失敗」ではありませんが、結果を疑うべきサインを含みます。特に型変換、未初期化変数、欠損値生成は頻出です。

自動変換

  • 文字と数値を比較・計算したときに起きる。
  • INPUT / PUT で明示変換へ直す。

未初期化変数

  • 変数名のスペルミスや、条件分岐で代入されない経路が原因になりやすい。
  • PROC CONTENTSPUTLOG で変数名と値を確認する。

欠損値生成

  • 無効な入力値、日付読み込み失敗、欠損を含む演算で発生する。
  • 入力データ、informat、計算式の順に確認する。

Logic

ロジックエラーの探し方

ロジックエラーは、構文としては正しくても、結果が問題文と違う状態です。見つけるには、途中結果を小さく検算します。

件数を確認

PROC PRINT(obs=)、ログの obs 数、PROC FREQ で意図せず行が増減していないか確認する。

型と長さを確認

PROC CONTENTS で文字 / 数値、文字長、format を確認する。文字長不足は値の切り詰めにつながる。

条件を確認

WHEREIF、日付定数、大小比較、欠損値の扱いを確認する。

グループ境界を確認

first. / last. が意図した単位で立っているか、BY 変数とソート順を確認する。

Practice

この項目の演習

自分で壊したコードを作り、ログから直す練習をします。試験前にこの作業をすると、ログを読む速度がかなり上がります。

構文解説: わざと壊したコードの読み方

  • set cert.orders の後にセミコロンがないため、次の if まで巻き込んで解釈される。
  • amount = "1000" は、数値変数と文字リテラルの比較になり、自動変換の NOTE が出やすい。
  • first.customer_id を使うには、事前ソートと DATA ステップ内の by customer_id; が必要。
/* 意図的な練習: どこを直すべきかログで確認する */
data work.bad;
  set cert.orders
  if amount = "1000" then flag = 1;
  if first.customer_id then total = 0;
  total + amount;
run;

直す観点

  • set 行のセミコロン。
  • 数値変数と文字リテラルの比較。
  • first.customer_id を使う前の by customer_id; とソート。

採点観点

  • 最初の ERROR を見つけられる。
  • WARNING / NOTE を結果品質のヒントとして読める。
  • 修正後に件数と合計で検算できる。