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