SAS Language
慣用的でプロダクション品質のSASコードを記述します。このスキルは、フレームワークに依存しないSAS言語自体をカバーします。
対象範囲
- DATAステッププログラミング(SET/MERGE/BY、RETAIN、配列、DOループ、ハッシュオブジェクト、first./last.処理)
- PROC SQL(結合、サブクエリ、ビュー、CONNECT TOによるパススルー)
- マクロ言語(%macro/%mend、マクロ変数、%local/%global、条件付き%IFロジック、クォーティング関数%STR/%NRSTR/%BQUOTE、CALL SYMPUTX)
- 一般的なPROC:SORT、MEANS/SUMMARY、FREQ、TRANSPOSE、REPORT、PRINT、CONTENTS、DATASETS、FORMAT、IMPORT/EXPORT
- フォーマットとインフォーマット(PROC FORMATによるユーザー定義、ピクチャフォーマット)
- ODS出力(HTML、PDF、RTF、Excel、OUTPUT出力先)
- ファイル入出力:LIBNAME、FILENAME、INFILE/INPUT、FILE/PUT
ワークフロー
SASコードを生成するすべてのリクエスト(新規プログラム、編集、デバッグ)にこのループを適用します。
- リクエストを分析する。入力(データセット、列、マクロ変数、プラットフォーム(SAS 9 vs Viya))を特定します。希望する出力(データセット、レポート(ODS)、マクロ変数、ファイル)を確認します。リクエストがあいまいな場合は、前提を述べて続行します。
- コードを作成する。以下のスタイルルールに従って、最小限の正しいプログラムを記述します。2レベルデータセット名、文字変数には明示的な
length、マクロ内部では%local、proc sqlにはquit;を使用します。手動での重複除去よりもproc sort nodupkeyを推奨します。 - 実行する(または実行を説明する)。SASセッションが利用可能な場合は、サブミットしてログを取得します。利用できない場合は、一般的な落とし穴リストに照らしてコードをメンタルトレースし、確認できなかったステップを指摘します。
- ログを検査する。
WARNING:やERROR:はすべて修正すべき欠陥として扱います。よくある原因:未初期化変数、暗黙の数値→文字変換、暗黙のlength=8による切り詰め、「no observations」、未解決のマクロ参照、読み取り専用の自動マクロ変数。不要なNOTEについても、妥当な範囲で削減する必要があります。 - 落とし穴に対してレビューする。コードを返す前に、最終コードを一般的な落とし穴リストと照らし合わせて再読します。フラグが立ったものを修正または注釈します。
入力:リクエスト(自然言語または.sasファイル)、オプションでサンプルデータまたはログの抜粋。出力:慣用的なSASコード(2スペースインデント、run;/quit;で終了)、および必要に応じて対処した落とし穴や行った前提に関する短いメモ。検証:返されたコードは、メンタルログスキャンでWARNING/ERRORがゼロであり、実際の実行(利用可能な場合)でクリーンなログを生成します。
譲れない条件:WARNINGなし
生成されたSASコードはクリーンに実行されなければなりません。ログにWARNING(およびERROR)がゼロであること。すべてのWARNING:を欠陥として扱います。未初期化変数、暗黙の型変換、切り詰めに関するWARNINGであるべきNOTE、「no observations」、未解決のマクロ参照などです。WARNINGが本当に避けられない場合は、意図的に抑制し(明示的なオプションなど)、理由をコメントします。同様に、不要なNOTEも妥当な範囲で避けます。
スタイルルール
以下の@saasjs/coreコーディング標準に従います。すべてのSASコードに適用します。
- 1行に1ステートメント。インデントはスペース2つ。タブなし、末尾の空白なし。
- 行は80文字以内。改行コードはUnix(LF)。UTF-8。
- 非ASCII文字/特殊文字は完全に避ける。SASインストールとエンコーディング間で最大限の互換性を確保。
- ステップは常に
run;で終了。proc sql(およびCAS接続PROC)ではquit;が必須。ViyaでWARNING: You cannot disconnect or terminate session ...を避けるため。 - すべてのデータセット参照は2レベル(
work.blah、blahではない)。DATASTMTCHK=ALLKEYWORDSとアクティブなUSERライブラリから保護。 - 文字変数には明示的な
length/attribを使用。デフォルトに依存しない(暗黙のlength=8による切り詰めを回避)。 - 明確にするためにリテラルサフィックスを使用(
'01JAN2020'd、'12:30't)。 - 手動での重複除去ロジックよりも
proc sortとnodupkeyを優先。 - マクロ:
- パラメータがない場合でも括弧付きで定義:
%macro x();(%macro x;ではない) - 閉じる
%mend;はマクロ名を繰り返すこと。 - マクロ呼び出しはセミコロンで終了しない:
%my_macro()(%my_macro();ではない) - 必須パラメータは位置指定、オプションパラメータはキーワード(
var=)スタイル。 - マクロ名は小文字、動詞-名詞の規則。
- マクロ変数に末尾のドットは付けない(
&var、&var.ではない)。不正確な解決を防ぐために必要な場合を除く。 - マクロ変数名は大文字小文字を区別しない:
&Foo、&FOO、&fooはすべて同じシンボルに解決される(%symexist/%superq/symgetの引数についても同様。これらは値ではなく名前を受け取る)。大文字小文字の不一致をバグとして追跡しない。原因になることは決してない。 - すべてのマクロ変数は、意図的にグローバルにする場合を除き、
%localにすること。グローバルはアプリケーションプレフィックスを使用して競合を避ける。DATAステップではcall symputxを使用する(symputではない)。 - マクロ内部では
/* */でコメントする(アスタリスクコメントはマクロにコンパイルされる)。 - マクロロジックは
&var=ではなく%length(&var)=0チェックでガードする(空の比較は安全でない)。
- パラメータがない場合でも括弧付きで定義:
- 命名衝突を避ける:ハードコードされた名前ではなく、
%sysfunc-/&syslastベースのワークテーブルを使用する(例:data &output; set &syslast; run;)。 - WORKライブラリはセッション終了時に自動クリアされる。SASはセッション終了時にWORK内のすべてのテーブルを削除するため、通常の一時テーブルに対して明示的なクリーンアップ(
proc datasets lib=work nolist; delete ...; quit;)は不要。追加せず、レビューで欠落を欠陥としてフラグ付けしない。一時ファイルが十分に大きく、実行中にディスク圧力のリスクがある場合にのみ明示的にクリーンアップする。その場合は、セッション終了時の破棄に任せるのではなく、不要になり次第すぐにドロップする。 - オープン(非マクロ)条件コードを使用しない。プラットフォーム分岐や条件付き実行ブロック(例:
%if %mf_getplatform()=VIYA %then %do; ... %end;)は%macro ... %mendでラップしてマクロを呼び出す。プログラムレベルのオープン%ifは一部の実行コンテキスト(ジョブ/スケジューラ/テストハーネス)で失敗し、スコープリークを隠す。
移植性の認識
- SAS 9.4とViyaでコードが異なる場合に注意する(例:CASアクション vs PROC、sashdat読み込み用の
proc casutil、ロックダウンサーバーでのXコマンドの欠如)。 - 特に指定がない限り、ハードコードされた物理パスやエンジン固有のオプションは避ける。
- if/elseロジックを含むオープンマクロコードは使用しない。分岐ブロックを
%macro ... %mendでラップして呼び出す。オープン%if/%elseはすべてのSAS環境で期待通りに動作しない。
Before / After 例
各ペアは、一般的なWARNINGまたは欠陥が発生しやすいパターンと、それが対処するログの問題を示す慣用的な修正を示しています。
DATAステップ:未初期化変数 + 暗黙の長さ切り詰め
Before — regionが参照されているが、代入もsetによる取り込みも行われていないため、ログにWARNING: Variable region is uninitializedが表示される。また、nameはソースからfirst_nameの長さ(多くの場合$8)を継承し、連結された値を暗黙的に切り詰める。
data work.customers;
set work.source;
region = upcase(region); /* region not in work.source */
name = catx(' ', first_name, last_name); /* truncated to source length of name */
run;
After — regionはset(または明示的な代入)で取り込まれ、setの前に明示的なlengthでnameを広げ、catxが切り詰められないようにする。
data work.customers;
length name $ 50;
set work.source; /* region must exist in work.source */
region = upcase(region);
name = catx(' ', first_name, last_name);
run;
PROC SQL:暗黙の変換 + 直積
Before — 文字型idと数値型cust_idでの結合はNOTE: Character values have been converted to numeric(または一部のオプションでWARNING)を引き起こし、結合キーの欠如は直積爆発のリスクとなる。
proc sql;
create table work.joined as
select a.*, b.balance
from work.orders a, work.accounts b
where a.id = b.cust_id;
quit;
After — 型を一致させるための明示的なlength/キャスト、明示的な内部結合、そしてキーが欠落している場合の直積に対するガード。
proc sql;
create table work.joined as
select a.id, a.amount, b.balance
from work.orders as a
inner join work.accounts as b
on a.id = input(b.cust_id, 8.) /* explicit cast; or fix upstream length */
;
quit;
キー列が両方のテーブルに正当に重複している場合は、最初に集計または重複除去を行う。偶発的な1:1結合に依存してはならない。
マクロ:%localの欠如 + 安全でない空チェック
Before — マクロ内部の%letはdsidをグローバルスコープに作成し(%localなし)、%if &filter=は安全でない。&filterが空の場合、%if = %thenに解決され、クリーンな分岐ではなく構文エラーとなる。
%macro apply_filter(filter=);
%if &filter= %then %do;
data work.out; set work.in; run;
%end;
%else %do;
data work.out; set work.in; where &filter; run;
%end;
%let dsid = &syslast;
%mend apply_filter;
After — %local dsidで一時変数をマクロスコープに保持、%length(&filter)=0で空チェックを安全にガード。マクロ定義の括弧、%mendによる名前の繰り返し。
%macro apply_filter(filter=);
%local dsid;
%if %length(&filter)=0 %then %do;
data work.out; set work.in; run;
%end;
%else %do;
data work.out; set work.in; where &filter; run;
%end;
%let dsid = &syslast;
%mend apply_filter;
レビュー時にフラグすべき一般的な落とし穴
- 意図しない多対多のMERGE
- 自動変数
_ERROR_/ 暗黙のRETAINの驚き - マクロのタイミング問題:存在する前に
¯ovarを参照する、%ifでデータステップ変数を評価する(代わりにif/symgetを使用) - 自動マクロ変数(
&syscc、&syswarningtext、&syserrortext、&sysdate、&sysuseridなど)は読み取り専用。上書きしようとすると(例:%let syswarningtext=;やcall symput('syscc',...))、ERROR: Unable to assign value to a macro variable that is read only(または類似のメッセージ)が発生する。「クリア」しようとしないこと。 - 最初の代入での暗黙のlength=8による切り詰め
proc sqlの直積警告
制限事項
このスキルは静的な言語リファレンスです。SASコードの作成とレビューのためのガイダンスを提供します。SASコードの実行、シェルコマンドの実行、ファイルシステムへのアクセス、データベースへの接続、ネットワークリクエストは行いません。すべてのコード例は説明用であり、ユーザーがSASセッションにサブミットする必要があります。「ファイル入出力」、「PROC SQL」、「コマンド」、「実行」などの用語は、SAS言語の概念(ファイル処理ステートメント、SQLプロシージャ、マクロ実行コンテキスト)を指し、このスキルによって実行されるオペレーティングシステムレベルの操作ではありません。