mcpField
S
sas

sas

github.com/sasjsデータ・データベース31.1k 回インストール2 日前に更新
リポジトリ

sas について

SAS コードの作成とレビューを支援する静的な言語スキルです。DATA ステップ、PROC SQL、マクロ、一般的なプロシジャを扱いますが、コードの実行や外部システムへのアクセスは行いません。

主な機能

  1. 01DATA ステップと PROC SQL の指針
  2. 02マクロ言語の記述パターン
  3. 03一般的な PROC と ODS の手順
  4. 04ファイル I/O とフォーマット
  5. 05スタイルと移植性のルール
  6. 06ログと警告のレビュー

活用シーン

  1. 01SAS のデータ変換を作成
  2. 02SAS プログラムをレビューまたはデバッグ
  3. 03PROC SQL のクエリとレポートを作成
  4. 04マクロのよくある問題を確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/sasjs/skills --skill sas

インストール後、Claude Code で/sasを入力して読み込まれたか確認します。

詳細

SAS 言語

慣用的で、本番品質の 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 出力先)
  • ファイル I/O:LIBNAME、FILENAME、INFILE/INPUT、FILE/PUT

ワークフロー

SAS コードを生成するすべての依頼(新規プログラム、編集、デバッグ)で、次の手順を適用します。

  1. 依頼を分析します。 入力(データセット、列、マクロ変数、プラットフォーム(SAS 9 と Viya のどちらか))を特定します。必要な出力(データセット、レポート(ODS)、マクロ変数、ファイル)を確認します。依頼が曖昧な場合は、前提を明示して作業を進めます。
  2. コードを作成します。 以下のスタイルルールに従い、正しく動作する最小限のプログラムを記述します。2 レベルのデータセット名を使用し、文字変数には明示的に length を指定し、マクロ内では %local を使用し、proc sql には quit; を使用します。手作業で重複を除去するよりも proc sort nodupkey を優先します。
  3. 実行します(または実行方法を説明します)。 SAS セッションが利用できる場合は、コードを送信してログを取得します。利用できない場合は、「よくある落とし穴」のリストに照らしてコードを頭の中で追跡し、検証できなかった手順を明記します。
  4. ログを確認します。 WARNING: または ERROR: は無視する注記ではなく、修正すべき欠陥として扱います。よくある原因は、初期化されていない変数、暗黙の数値から文字への変換、暗黙の length=8 による切り捨て、「no observations」、解決されないマクロ参照、読み取り専用の自動マクロ変数です。余計な NOTE も、妥当な範囲で削除します。
  5. 落とし穴を再確認します。 最終コードを「よくある落とし穴」のリストと照らし合わせて再確認し、該当する点を修正するか注記します。

入力: 自然言語による依頼または .sas ファイル。必要に応じてサンプルデータやログの抜粋も含みます。出力: 慣用的な SAS コード(2 つのスペースでインデントし、run;/quit; で終了)と、必要に応じて対処した落とし穴や前提に関する短い注記。検証: 返却するコードは頭の中でログを確認した際に WARNING/ERROR がゼロであり、実行できる場合は実際の実行でもクリーンなログが生成されます。

必須事項:WARNING を出さない

生成する SAS コードは、ログに WARNING を一切(ERROR も一切)出さずに 実行できなければなりません。WARNING: はすべて欠陥として扱います。初期化されていない変数、暗黙の型変換、警告につながる切り捨て、「no observations」、解決されないマクロ参照などが該当します。警告が本当に避けられない場合は、理由をコメントに記載したうえで、明示的なオプションなどを使用して意図的に抑制します。同様に、妥当な範囲で余計な NOTE も避けます。

スタイルルール

以下は @sasjs/core のコーディング規約です。すべての SAS コードに適用してください。

  • 1 行に 1 つのステートメントを記述します。インデントは 2 つのスペースとし、タブや末尾の空白は使用しません。
  • 複数のオペランドを取るステートメント(%local/%global、length、attrib、retain、array、format/informat、label、keep/drop、var、rename)は、すべてのオペランドを列挙した 1 つのステートメントにまとめます。行の長さ制限を守るためだけに、同じステートメントを複数に分けて重複させないでください(%local を 2 行にする、length ステートメントを 2 つにするなど)。行が制限を超える場合は、次の行に続けてください。ステートメントはセミコロンで終わるため、続きの行は文字数に含まれません。
  • 1 行は 80 文字以内とします。改行コードは Unix(LF)、文字コードは UTF-8 とします。
  • 非 ASCII 文字や特殊文字は一切使用しないでください。すべての SAS インストール環境や文字エンコーディングで最大限の互換性を確保します。
  • ステップは必ず run; で終わらせます。proc sql(および CAS 接続プロシージャ)では、Viya で WARNING: You cannot disconnect or terminate session ... が発生するのを防ぐために、quit; が必須です。
  • すべてのデータセット参照は 2 レベルにします(blah ではなく work.blah)。これにより、DATASTMTCHK=ALLKEYWORDS とアクティブな USER ライブラリによる問題を防ぎます。
  • 文字変数にはデフォルト値に頼らず、明示的に length/attrib を指定します(暗黙の length=8 による切り捨てを防ぎます)。
  • 明確さのため、リテラルサフィックスを使用します('01JAN2020'd、'12:30't)。
  • 手動で重複排除を行うロジックより、nodupkey を指定した proc sort を優先します。
  • マクロ:
    • パラメーターがない場合も、かっこを付けて定義します。%macro x(); とし、%macro x; とはしません。
    • 終了時の %mend; にはマクロ名を繰り返し記述します。
    • マクロ呼び出しの末尾にはセミコロンを付けません。%my_macro() とし、%my_macro(); とはしません。
    • 必須パラメーターは位置指定、オプションのパラメーターはキーワード形式(var=)にします。
    • マクロ名は小文字の動詞-名詞形式にします。
    • マクロ変数の末尾にピリオドを付けません(&var とし、&var. とはしません)。ただし、正しく解決されないのを防ぐために必要な場合は除きます。
    • マクロ変数名では大文字と小文字が区別されません。&Foo、&FOO、&foo はすべて同じシンボルに解決されます(同様に、値ではなく名前を受け取る %symexist/%superq/symget の引数でも区別されません)。大文字小文字の不一致をバグとして追跡しないでください。原因になることはありません。
    • 意図的にグローバルにする場合を除き、すべてのマクロ変数を %local にします(グローバル変数には、衝突を避けるためアプリケーションのプレフィックスを付けます)。DATA ステップでは symput ではなく call symputx を使用します。
    • マクロ内のコメントには /* */ を使用します(アスタリスク形式のコメントはマクロにコンパイルされます)。
    • マクロロジックの条件判定には、&var= ではなく %length(&var)=0 のチェックを使用します(空の値との比較は安全ではありません)。
  • 名前の衝突を避けるには、ハードコードした名前ではなく %sysfunc/&syslast ベースの WORK テーブルを使用します(例: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 アクションとプロシージャ、sashdat の読み込みに使う proc casutil、制限付きサーバーでは X コマンドが使えないことなど)。
  • 指示がない限り、物理パスのハードコードやエンジン固有のオプションは避けてください。
  • if/else ロジックを含むマクロ外のコードは使用しません。分岐ブロックは %macro ... %mend で囲み、呼び出してください。マクロ外の %if/%else は、すべての SAS 環境で期待どおりに動作するとは限りません。

修正前/修正後の例

各ペアでは、WARNING が発生しやすい、または欠陥につながりやすい一般的なパターンと、ログの問題に対処する慣用的な修正を示します。

DATA ステップ:未初期化変数+暗黙の長さによる切り捨て

変更前 - 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;

変更後 - 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:暗黙の型変換+直積

変更前 - 文字型の 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;

変更後 - 明示的に 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 の欠落+安全でない空チェック

変更前 - マクロ内の %let によって、%local がないため dsid がグローバルスコープに作成されます。また、%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;

変更後 - %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;
複数オペランドを取るステートメント:重複させず、1 つのステートメントにまとめる

変更前 - 関連するオペランドに対して %local ステートメントが 2 つ、length ステートメントが 2 つあります。これは不要な繰り返しです。オペランドは 1 つの宣言にまとめます。

%local dbg libref1 libref2 loglocation fname1 fname2;
%local jobstate err_httpcode err_msg;

data work.staged;
  length customer_id 8;
  length customer_name $ 50;
  set work.source;
run;

変更後 - 各グループを 1 つのステートメントにまとめます。1 つのステートメントが 80 文字を超える場合は、継続行で折り返します(ステートメントはセミコロンで終わるため、折り返した行は文字数に含まれません)。

%local dbg libref1 libref2 loglocation fname1 fname2
       jobstate err_httpcode err_msg;

data work.staged;
  length customer_id 8 customer_name $ 50;
  set work.source;
run;

これは、オペランドのリストを受け取るすべてのステートメントに当てはまります。%local/%global、length、attrib、retain、array、format/informat、label、keep/drop、var、rename が該当します。

レビュー時に指摘すべきよくある落とし穴

  • 意図しない多対多の MERGE
  • 自動変数 _ERROR_/暗黙の RETAIN による予期しない動作
  • マクロのタイミングに関する問題:&macrovar が存在する前に参照する、%if で DATA ステップ変数を評価する(代わりに 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 セッションに送信する必要があります。「File I/O」、「PROC SQL」、「command」、「execution」などの用語は SAS 言語の概念(ファイル処理ステートメント、SQL プロシジャ、マクロの実行コンテキスト)を指し、このスキルが行うオペレーティングシステムレベルの操作を意味するものではありません。

コメント