Community라이팅 & 에디팅github.com

sasjs/skills

SASjs 생태계와 SAS 프로그래밍 언어를 위한 에이전트 스킬

skills란 무엇인가요?

이 스킬은 AI 에이전트(Claude Code, Cursor 등)가 SAS 언어로 생산성 높은 프로덕션 코드를 작성하고 검토할 수 있도록 설계된 상세한 스타일 가이드입니다. DATA 스텝 프로그래밍, PROC SQL, 매크로 언어, ODS 출력 등 SAS 프로그래밍의 핵심 범위를 다루며, 코드 작성부터 로그 검사, 일반적 함정 점검까지의 5단계 워크플로우를 제공합니다. SAS 9.4와 Viya 환경 모두를 고려한 이식성을 강조하며, '로그에 WARNING/ERROR가 단 하나도 없어야 한다'는 엄격한 원칙을 비타협적으로 요구합니다. 각 스타일 규칙과 함께 Before/After 예제 및 CHECKLIST를 제공하여, 초보자부터 숙련자까지 일관된 품질의 SAS 코드를 생성할 수 있도록 돕습니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add sasjs/skills

Installed? Explore more 라이팅 & 에디팅 skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

SAS Language

idiomatic하고 프로덕션 품질의 SAS 코드를 작성합니다. 이 스킬은 어떤 프레임워크와도 무관하게 SAS 언어 자체를 다룹니다.

범위

  • DATA 스텝 프로그래밍 (SET/MERGE/BY, RETAIN, 배열, DO 루프, 해시 객체, first./last. 처리)
  • PROC SQL (조인, 서브쿼리, 뷰, CONNECT TO를 사용한 패스스루)
  • 매크로 언어 (%macro/%mend, 매크로 변수, %local/%global, 조건부 %IF 로직, quoting 함수 %STR/%NRSTR/%BQUOTE, CALL SYMPUTX)
  • 일반적인 PROC: SORT, MEANS/SUMMARY, FREQ, TRANSPOSE, REPORT, PRINT, CONTENTS, DATASETS, FORMAT, IMPORT/EXPORT
  • Format과 informat (PROC FORMAT을 통한 사용자 정의, picture format)
  • ODS 출력 (HTML, PDF, RTF, Excel, OUTPUT destination)
  • 파일 I/O: LIBNAME, FILENAME, INFILE/INPUT, FILE/PUT

워크플로우

SAS 코드를 생성하는 모든 요청(새 프로그램, 편집, 디버그)에 대해 다음 루프를 적용하십시오.

  1. 요청 분석. 입력값(데이터셋, 컬럼, 매크로 변수, 플랫폼(SAS 9 vs Viya))을 식별합니다. 원하는 출력값(데이터셋, 보고서(ODS), 매크로 변수, 파일)을 확인합니다. 요청이 모호하면 가정을 명시하고 진행합니다.
  2. 코드 초안 작성. 아래 스타일 규칙을 따라 최소한의 올바른 프로그램을 작성합니다. 2단계 데이터셋 이름, 문자 변수에 대한 명시적 length, 매크로 내부의 %local, proc sql에 대한 quit;을 사용합니다. 수동 중복 제거보다 proc sort nodupkey를 선호합니다.
  3. 실행(또는 실행 결과 설명). SAS 세션을 사용할 수 있으면 제출하고 로그를 캡처합니다. 그렇지 않으면 일반적인 함정 목록을 기준으로 코드를 mentally 추적하고, 확인할 수 없었던 단계를 언급합니다.
  4. 로그 검사. WARNING: 또는 ERROR:를 무시할 메시지가 아닌 수정해야 할 결함으로 처리합니다. 일반적인 원인: 초기화되지 않은 변수, 암시적 숫자→문자 변환, 암시적 length=8로 인한 잘림, "관측치 없음", 확인할 수 없는 매크로 참조, 읽기 전용 자동 매크로 변수. 불필요한 NOTE도 합리적인 범위 내에서 제거해야 합니다.
  5. 함정 검토. 코드를 반환하기 전에 일반적인 함정 목록과 대조하여 최종 코드를 다시 읽습니다. 플래그가 지정된 항목을 수정하거나 주석을 답니다.

입력값: 요청(자연어 또는 .sas 파일), 선택적으로 샘플 데이터나 로그 발췌문. 출력값: idiomatic SAS 코드(2칸 들여쓰기, run;/quit;으로 종료) 및 필요한 경우 해결된 함정이나 가정에 대한 짧은 설명. 검증: 반환된 코드는 WARNING/ERROR가 전혀 없는 mental 로그 스캔을 통과하며, 가능한 경우 실제 실행에서 깔끔한 로그를 생성합니다.

비타협: WARNING 없음

생성된 SAS 코드는 로그에 WARNING이 하나도 없어야 합니다(그리고 ERROR도 없어야 합니다). 모든 WARNING:을 결함으로 처리하십시오: 초기화되지 않은 변수, 암시적 유형 변환, 경고로 간주되어야 하는 잘림 메시지, "관측치 없음", 확인할 수 없는 매크로 참조 등. 경고가 정말 피할 수 없는 경우 의도적으로 억제하고(예: 명시적 옵션) 그 이유를 주석으로 남기십시오. 마찬가지로 불필요한 NOTE도 합리적인 범위 내에서 피하십시오.

스타일 규칙

이 규칙은 @sasjs/core 코딩 표준을 따릅니다. 모든 SAS 코드에 적용하십시오:

  • 한 줄에 하나의 명령문; 들여쓰기 = 공백 2칸, 탭 없음, 후행 공백 없음
  • 줄 길이 80자 이하; unix(LF) 줄 끝; UTF-8
  • 비ASCII/특수 문자는 완전히 사용하지 않음 — 다양한 SAS 설치 및 인코딩에서 최대 호환성 보장
  • 항상 단계를 run;으로 종료; proc sql(및 CAS 연결 프로시저)의 경우 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)
  • 수동 중복 제거 로직보다 nodupkey가 있는 proc sort 선호
  • 매크로:
    • 매개변수가 없더라도 괄호와 함께 정의: %macro x;가 아닌 %macro x();
    • 닫는 %mend;는 매크로 이름을 반복해야 함
    • 매크로 호출은 세미콜론으로 종료되지 않음: %my_macro();가 아닌 %my_macro()
    • 필수 매개변수는 위치 지정; 선택적 매개변수는 키워드(var=) 스타일
    • 매크로 이름은 소문자, 동사-명사 규칙
    • 뒤에 점이 없는 매크로 변수(&var.가 아닌 &var), 잘못된 해석을 방지해야 하는 경우는 제외
    • 매크로 변수 이름은 대소문자를 구분하지 않음: &Foo, &FOO, &foo는 모두 동일한 심볼로 해석됨(%symexist/%superq/symget 인수도 마찬가지이며, 이들은 값이 아닌 NAME을 받음). 대소문자 불일치를 버그로 추적하지 마십시오 — 원인이 될 수 없습니다.
    • 모든 매크로 변수는 의도적으로 전역이 아닌 한 %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는 일부 실행 컨텍스트(작업/스케줄러/테스트 harness)에서 실패하고 범위 누출을 숨깁니다.

이식성 인식

  • SAS 9.4와 Viya 간 코드 차이점을 기록하십시오(예: CAS 액션 vs 프로시저, sashdat 로딩을 위한 proc casutil, 잠긴 서버에서 X 명령어 불가)
  • 요청하지 않는 한 하드코딩된 물리적 경로와 엔진별 옵션을 피하십시오
  • 열린 매크로 코드에 if/else 로직을 사용하지 마십시오: 분기 블록을 %macro ... %mend로 감싸고 호출하십시오 — 열린 %if/%else는 모든 SAS 환경에서 예상대로 작동하지 않습니다.

Before / After 예제

각 쌍은 일반적인 WARNING 또는 결함이 발생하기 쉬운 패턴과 해결하는 로그 문제와 함께 idiomatic한 수정을 보여줍니다.

DATA 스텝: 초기화되지 않은 변수 + 암시적 길이 잘림

Before — region이 참조되었지만 set을 통해 할당되거나 가져오지 않았으므로 로그에 WARNING: Variable region is uninitialized가 표시됩니다. 또한 name은 소스에서 first_name의 길이를 상속받아(종종 $8) 연결된 값을 자동으로 잘라냅니다:

data work.customers;
  set work.source;
  region = upcase(region);                 /* region이 work.source에 없음 */
  name = catx(' ', first_name, last_name); /* name의 소스 길이로 잘림 */
run;

After — region이 set을 통해 가져오거나(또는 명시적으로 할당) set 앞에 명시적 length가 name을 넓혀서 catx가 잘리지 않도록 합니다:

data work.customers;
  length name $ 50;
  set work.source;                          /* region은 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/cast로 유형 일치, 명시적 inner join, 키가 없는 경우 카티전 방지:

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.) /* 명시적 캐스트; 또는 상류 길이 수정 */
  ;
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 예상치 못한 동작
  • 매크로 타이밍 문제: 존재하기 전에 &macrovar 참조, DATA 스텝 변수를 평가하는 %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 세션에 제출해야 합니다. "File I/O", "PROC SQL", "command", "execution"과 같은 용어는 이 스킬이 수행하는 운영 체제 수준의 작업이 아닌 SAS 언어 개념(파일 처리 명령문, SQL 프로시저, 매크로 실행 컨텍스트)을 나타냅니다.

관련 스킬