2016-09-02 36 views
1

我有一個宏在給定數據集中查找變量名稱。如果宏查找的變量名稱丟失,丟失的變量名被添加到一個表:proq sql宏;遍歷列表

%macro miss(ds, var); 
    %local rc dsid result; 
    %let dsid=%sysfunc(open(&ds)); 
    %if %sysfunc(varnum(&dsid,&var)) > 0 %then %do; 
     %put &var present; 
    %end; 
    %else %do; 
     insert into work.compare(missing) values("&var") 
    %end; 
%mend; 

proc datasets library=work nolist nodetails; 
    delete compare; 
run; 

proc sql; 
    create table work.compare (missing char(15)); 
%miss(ctr.panup_in, u_name); 
quit; 

proc print noobs data=work.compare; 
run; 

這種檢查需要55不同的變量名來運行。目前,我只列出每一個作爲一個

%miss(ctr.panup_in, varname); 

線。

出於實際的原因,我想指定變量列表作爲列表,例如%let dictionary = var1 var2 var3等。我現在正在努力尋找一種方法讓宏在循環變量列表中循環。到目前爲止,我所嘗試的所有內容都會導致「Stament is not valid」錯誤,其中包含

insert into work.compare(missing) values("&var") 

命令。

有沒有人有任何建議如何做到這一點?

+0

如果你知道你有55個變量,爲什麼不在宏內使用datastep而不是sql,並且do循環和掃描函數添加每個變量? – kl78

+0

我會推薦一個數據步驟,然後調用execute來代替。以下是如何通過宏變量循環https://gist.github.com/statgeek/9603186 – Reeza

+0

@ 20salmon如果您仔細查看我的代碼示例,您將找到一個比較宏,比較兩個數據集之間的變量。 – Reeza

回答

1

這循環一組變量,其中變量 由「|」分隔。任何其他分隔符都可以使用 並在掃描功能中指定。

%macro loop(varlist); 
%let i=1; 
%do %while (%scan(&varlist, &i, |) ^=%str()); 
%let var=%scan(&varlist, &i, |); 
%put &var; 

*rest of SAS code goes here; 

*Increment counter; 
%let i=%eval(&i+1); 
%end; 
%mend; 
%let temp=a|b|c|d|e; 
%loop(&temp); 
1

你真的需要檢查。您可以定義一個所有要添加的變量的零obs數據集,如果它們丟失並使用未執行的SET來包含它們。

*All variables that you might want to add; 
data master0; 
    attrib a length=8; 
    attrib b length=$15; 
    attrib c length=$15; 
    stop; 
    call missing(of _all_); 
    run; 

*Subset of the variable in master0; 
data a; 
    do a = 1 to 10; 
     output; 
     end; 
    retain X 1; 
    run; 

*Create new data with master + a variables; 
data a_all; 
    set a; 
    if 0 then set master0; 
    run; 
proc print; 
    run; 

您可以擺脫不想使用修改來更新所有變量的主變量。

*Create new data with with only wanted variables from master0; 
data a_all; 
    stop; 
    set master0; 
    run; 
data a_all; 
    if 0 then modify a_all; 
    set a; 
    output; 
    run; 
1

另一種選擇是將變量存儲在表中 - 很可能它們已經在一個表中。也許dictionary.columns?

事實上,你可以簡單地通過dictionary.columns完成整個過程。例如:

%let varlist=name age novar; 

data values_to_check; 
    length name $32; 
    do _i = 1 to countw("&varlist."); 
    name= scan("&varlist.",_i); 
    output; 
    end; 
run; 


proc sql; 

    create table compare as 
    select V.name as missing 
    from values_to_check V 
    left join 
    (Select * from dictionary.columns 
     where memname='CLASS' and libname='SASHELP') D  
     on upcase(V.name)=upcase(D.name) 
    where D.name is null 
    ; 
    quit; 

也就是說,如果你沒有創建的數據集,如果它已經存在,當然更容易 - 無論是作爲確實存在,或者只是直接通過創建它的另一個數據集中的變量列表數據線或類似的。可能性是你有一些數據片有這個信息,但不僅僅是硬編碼%讓聲明。

一個例子,它標識變量CLASSFITCLASS(無論是在SASHELP庫):

proc sql;  
    create table compare as 
    select V.name as missing 
    from 
     (Select * from dictionary.columns 
     where memname='CLASSFIT' and libname='SASHELP') V 
    left join 
    (Select * from dictionary.columns 
     where memname='CLASS' and libname='SASHELP') D  
     on upcase(V.name)=upcase(D.name) 
    where D.name is null 
    ; 
    quit; 
0

如果你真的想與不在你的數據集,那麼你可以只使用名稱的表一個數據步驟,並消除使用宏或PROC SQL的複雜性。

%let ds=sashelp.class; 
%let varlist=age sex gender ; 
data compare; 
    length missing $32 ; 
    dsid=open("&ds"); 
    do i=1 to countw("&varlist"); 
    missing = scan("&varlist",i); 
    if not varnum(dsid,missing) then output; 
    end; 
    rc=close(dsid); 
    stop; 
    keep missing; 
run; 

現在宏解決方案可能會有用的是,如果您想傳遞列表並獲取另一個列表,而不生成任何代碼。

%macro miss(ds, varlist); 
%local dsid i var result; 
%let dsid=%sysfunc(open(&ds)); 
%if (&dsid) %then %do; 
    %do i=1 %to %sysfunc(countw(&varlist)); 
    %let var=%scan(&varlist,&i); 
    %if not %sysfunc(varnum(&dsid,&var)) %then %let result=&result &var; 
    %end; 
    %let rc=%sysfunc(close(&dsid)); 
%end; 
%else %let result=&varlist; 
&result. 
%mend miss; 

這樣你就可以在聲明的中間調用宏,就像函數調用一樣。

%put Missing variables are: %miss(sashelp.class,age sex gender);