SAS Base Programming · 35-40%

データ管理

出題比率が最も大きい領域。並べ替え、条件分岐、属性変更、累計、関数、型変換、DO ループ、転置、マクロ変数をまとめて固めます。

試験対策ハブ · 詳細項目

Goal

この項目で到達する状態

入力済みデータを、分析やレポートに使える形へ変換できること。試験では、DATA ステップの基礎力がそのまま得点に直結します。

01

PROC SORT と重複削除

PROC SORT は、BY 処理、マージ、レポートの前提になります。元データを残すなら OUT= を使います。

構文解説: 並べ替えとキー重複削除

  • data= は入力データセット、out= はソート後に作るデータセットを指定する。
  • by customer_id order_date; は、顧客 ID、日付の順で並べ替える。
  • nodupkey は、BY 変数の値が重複する行を落とす。
proc sort data=cert.orders out=work.orders_sorted;
  by customer_id order_date;
run;

proc sort data=work.orders_sorted out=work.unique_customers nodupkey;
  by customer_id;
run;
注意

NODUPKEY は BY 変数が同じ行の重複を落とします。行全体が完全一致する重複と混同しないようにします。

02

IF-THEN/ELSE と DO/END

条件に応じた変数作成や再分類は頻出です。複数ステートメントを条件付きで実行する場合は DOEND でまとめます。

構文解説: 条件分岐の読み方

  • length は文字変数の長さを、代入より前に決める。
  • if ... then は条件に合う場合だけ代入する。
  • else if は前の条件に合わなかった場合だけ次を判定する。
  • do; ... end; は複数のステートメントを 1 つの条件にまとめる。
data work.orders_flagged;
  set work.orders_sorted;
  length amount_band $ 8 status $ 12;

  if amount >= 10000 then amount_band = "High";
  else if amount >= 3000 then amount_band = "Middle";
  else amount_band = "Low";

  if missing(customer_id) then do;
    status = "Review";
    review_reason = "Missing ID";
  end;
  else status = "OK";
run;

03

代入文、LENGTH、LABEL、FORMAT

文字変数の長さは、最初に現れた定義で決まります。代入より前に LENGTH を置く癖をつけると、値の切り詰めを防げます。

構文解説: 変数属性を先に整える

  • length region_group $ 12; は文字変数の長さを 12 バイトにする。
  • rename=(old_region=region) は読み込み時に変数名を変える。
  • label は変数の説明、format は表示形式を指定する。
  • in (...) は、値が指定リストに含まれるかを判定する。
data work.orders_clean;
  length region_group $ 12;
  set work.orders_flagged(rename=(old_region=region));
  label amount = "Order Amount"
        order_date = "Order Date";
  format amount comma12. order_date yymmdd10.;

  if region in ("Tokyo", "Kanagawa", "Chiba", "Saitama") then region_group = "Kanto";
  else region_group = "Other";
run;

RENAME=

  • 変数名そのものを変更する。
  • 読み込み時・書き出し時のデータセットオプションとして使える。

LABEL / FORMAT

  • 表示上の説明と見た目を変える。
  • 値そのものの型や保存値を変えるわけではない。

Missing Values

欠損値を含む計算は、演算子と関数で結果が変わる

数値計算では、欠損値の扱いがロジックエラーになりやすいです。+ 演算子と SUM 関数、SUM ステートメントの違いを意識します。

構文解説: 横方向の合計と累計

  • total_operator = a + b; は通常の足し算で、欠損の影響を受ける。
  • sum(a, b) は非欠損値を合計する関数。
  • running_total + a; は SUM ステートメントで、前行までの値を保持して累計する。
  • datalines; は例示用の小さな入力データをコード内に置く。
data work.missing_practice;
  input a b;
  total_operator = a + b;
  total_function = sum(a, b);
  running_total + a;
datalines;
10 5
.  7
3  .
;
run;

押さえる違い

  • a + b は、どちらかが欠損なら結果も欠損になりやすい。
  • sum(a,b) は、欠損を無視して非欠損値を合計する。
  • running_total + a; は SUM ステートメントで、値を自動的に保持する。

試験での見抜き方

  • 「累計」「小計」が出てきたら SUM ステートメントや RETAIN を疑う。
  • 横方向の合計で欠損を無視したいなら SUM 関数を使う。
  • ログに欠損値生成の NOTE が出たら、計算式を確認する。

04

BY グループ、first. / last.、RETAIN、SUM ステートメント

グループごとの小計や累計は、DATA ステップの核です。BY 変数でソートし、グループの先頭で初期化し、最後で出力します。

構文解説: グループ単位の 1 行サマリー

  • proc sort ... by customer_id order_date; で顧客別・日付順に並べる。
  • by customer_id; は DATA ステップ内でグループ境界を使う宣言。
  • first.customer_id で顧客ごとの初期化を行う。
  • total_amount + amount; は合計を保持しながら加算する。
  • last.customer_id の行だけ output して、顧客ごとに 1 行へまとめる。
proc sort data=work.orders_clean out=work.orders_by_customer;
  by customer_id order_date;
run;

data work.customer_summary;
  set work.orders_by_customer;
  by customer_id;
  if first.customer_id then do;
    total_amount = 0;
    order_count = 0;
    first_order = order_date;
  end;
  total_amount + amount;
  order_count + 1;
  if last.customer_id then do;
    last_order = order_date;
    output;
  end;
  format first_order last_order yymmdd10. total_amount comma12.;
  keep customer_id total_amount order_count first_order last_order;
run;

BY Groups

first. / last. は「行」ではなく「グループ境界」を見る

first.customer_idlast.customer_id は、BY グループの始まりと終わりを示します。複数の BY 変数を使うと、どの単位で初期化するかが得点差になります。

構文解説: 複数 BY 変数の境界

  • by region customer_id order_date; は、地域、顧客、日付の順に並べる。
  • DATA ステップ側の by region customer_id; は、地域内の顧客単位で境界を作る。
  • first.customer_id で顧客ごとに初期化し、last.customer_id で顧客ごとの結果を出す。
proc sort data=work.orders_clean out=work.orders_by_region_customer;
  by region customer_id order_date;
run;

data work.region_customer_summary;
  set work.orders_by_region_customer;
  by region customer_id;
  if first.customer_id then do;
    customer_total = 0;
    customer_count = 0;
  end;
  customer_total + amount;
  customer_count + 1;
  if last.customer_id then output;
  keep region customer_id customer_total customer_count;
run;
読む順番

by region customer_id; の場合、顧客単位の集計なら first.customer_id で初期化します。地域全体の集計なら first.region を使うため、問題文の「単位」を先に確認します。

05

文字・数値・日付関数と型変換

関数は範囲が広いので、試験ガイドにある代表関数をタスク別に覚えます。型変換は INPUTPUT を明示的に使います。

文字SCAN区切り文字で文字列を分解する。名前、コード、住所などの抽出に使う。
文字SUBSTR固定位置から一部を取り出す。商品コードや年月文字列に使う。
文字TRIM後続ブランクを取り除く。文字列連結前の余分な空白対策に使う。
文字UPCASE / LOWCASE大小文字をそろえる。コード値やステータスの比較前に使う。
数値SUM欠損を無視して合計する。単純な + とは欠損時の挙動が違う。
数値MEAN / ROUND / INT平均、丸め、整数化。指定された表示や判定に合わせて使う。
数値SMALLEST / LARGEST複数値の中から小さい順・大きい順の値を取り出す。
日付INTCK2 つの日付の間にある期間境界数を返す。
日付INTNX指定した間隔だけ日付を進め、月初・月末などの位置を制御する。
日付MDY / TODAY日付値を作る。固定日付と実行日基準の計算を分ける。
日付YEAR / QTR / MONTH / DAYSAS 日付値から年、四半期、月、日を取り出す。

構文解説: 関数をタスクに対応させる

  • scansubstr は、文字列から必要部分を取り出す。
  • put(order_date, yymmddn8.) は日付値を文字列に変換し、後続の substr で年月を抜き出す。
  • round(amount, 100) は 100 単位で丸める。
  • intck は期間数、intnx は指定期間だけ進めた日付を求める。
data work.function_practice;
  set work.orders_clean;
  product_prefix = scan(product_code, 1, "-");
  year_month = substr(put(order_date, yymmddn8.), 1, 6);
  amount_round = round(amount, 100);
  months_from_order = intck("month", order_date, today());
  next_month_start = intnx("month", order_date, 1, "b");
  char_amount = put(amount, comma12.);
  num_amount = input(char_amount, comma12.);
run;

Conversion

型変換はログに頼らず、意図をコードに書く

SAS は必要に応じて自動変換を行いますが、ログに NOTE が出て、想定外の欠損や比較ミスにつながることがあります。試験では明示変換を書けることが重要です。

構文解説: INPUT と PUT の向き

  • input(amount_char, comma12.) は、文字の金額を数値に変換する。
  • put(order_date, yymmn6.) は、数値の日付値を年月文字列に変換する。
  • format amount_num comma12.; は、数値の保存値は変えず表示だけ整える。
data work.converted;
  set work.orders_clean;
  amount_num = input(amount_char, comma12.);
  order_month = put(order_date, yymmn6.);
  format amount_num comma12.;
run;

INPUT

  • 文字値を、informat を使って数値へ変換する。
  • 金額文字列、日付文字列、コード化された数値の変換で使う。

PUT

  • 数値を、format を使って文字へ変換する。
  • 日付を年月文字列にする、数値コードを表示用文字列にする場面で使う。

06

DO ループ、PROC TRANSPOSE、マクロ変数

DO ループは繰り返し処理、PROC TRANSPOSE はデータの縦横変換、マクロ変数はプログラム保守に使います。

構文解説: 繰り返し、転置、マクロ変数

  • %let はプログラム中で再利用する値をマクロ変数に入れる。
  • do month = 1 to 12; は 1 から 12 まで繰り返す。
  • mdy(month, 1, &target_year.) は月・日・年から SAS 日付値を作る。
  • proc transposevar は転置する値、id は列名になる値、by はグループ単位を指定する。
%let target_year = 2026;
%let outlib = work;

data &outlib..monthly_targets;
  do month = 1 to 12;
    target_date = mdy(month, 1, &target_year.);
    output;
  end;
  format target_date yymmdd10.;
run;

proc transpose data=work.sales_long
               out=work.sales_wide(prefix=month_)
               name=source_variable;
  by customer_id;
  id month;
  var amount;
run;
BY を使う前提

PROC TRANSPOSEBY を使う場合、対象データは BY 変数でソート済み、または適切にインデックス化されている必要があります。

マクロ変数のドット

&outlib..monthly_targets のようにドットが 2 つ見えるのは、1 つ目がマクロ変数名の終端、2 つ目がライブラリとメンバ名の区切りです。