2017-01-09 223 views
1

基本上我正在寫一個宏,將作爲參數我的輸入表,輸出表和一個變量列表。我的變量列表顯示爲一個參數,爲此我使用空格字符作爲分隔符。 我的宏應該將我的列表分隔成nbvar宏 - 變量,它將包含我的(SAS)變量的名稱。然後,我使用datastep將我的(SAS)變量從其原始字符格式輸入到數值中。SAS宏:循環來創建變量

這裏是我的一段代碼:

%macro convert_car_to_num(input,output,listvar); 

/* First I split my list into nbvar variables named var&i 
%qscan to avoid macro resolution of names, not really necessary here 
but still works fine. My delimiter is space character, hence 
%str() in the %qscan*/ 

%let nbvar=%sysfunc(countw(&listvar)); 
%do i = 1 %to &nbvar; 
    %let var&i=%qscan(&listvar,&i,%str()); 
%end; 

/*Here is my data step. &&var&i_num is resolved just fine*/ 
data &output; 
set &input; 
%do i = 1 %to &nbvar; 
    &&var&i.._num = input(&&var&i,BEST16.); 
%end; 
run; 

%mend; 

由於& &變種&我.._ NUM和& & VAR &我都解決了,我希望我的代碼工作,但我的日誌顯示:

varname_num

解析名稱「varname」加下劃線。我發現後有一點點:

錯誤180-322:語句無效或使用不正確的順序。

這通常是錯位分號的標準錯誤。然而,我知道我的宏觀變量都解決了,因爲MPRINT顯示:

MPRINT(CONVERT_CAR_TO_NUM):(varname的,BEST16)varname_num =輸入

注:受宏觀變量 「VAR26」 行產生。

MPRINT(CONVERT_CAR_TO_NUM):run;

其中,varname是我列表中第26個變量的正確名稱,表示分辨率工作得很好。

爲了讓我更無法理解的,同一段代碼,我將表明:

&&var&i.. = input(&&var&i,BEST16.); 

DOES編譯,即使它不符合預期的結果結束(變量仍然是char )。

類似地,用相同的代碼:

&&var&i.._num = &&var&i; 

不任一編譯。

我也測試了改變我的宏觀變量的名稱num_ & & &變種i或n & &變種&我,甚至是第一次聲明一個宏觀變量「名」,其中將包括& & VAR &我,都是爲了同樣的效果。不選擇與初始變量相同的名稱似乎會導致代碼顯示180錯誤。

我想問題在於試圖聲明一個變量,知道我寫的以前和類似的一段代碼確實有效,datastep是一個比較(將變量列表中的缺失值也變爲零) :

data &output; 
set &input; 
    %do i = 1 %to &nbvar; 
     if &&var&i = . then &&var&i = 0; 
    %end; 
run; 

但對於這種同一段代碼,如果我嘗試(使用任何名稱再次,對於這個問題)創建一個新的變量,寫作:

if num_&&var&i = . then &&var&i = 0; 

我發現我自己的解決名稱再次加下劃線,但現在指向以下錯誤:

ERROR 22-322:語法錯誤,在需要下列之一:,!!,&,(,*,**,+, - ,/,;,<, < =,<> =,>,> =,AND,EQ,GE,GT,IN,LE,LT,MAX,MIN,NE,NG,NL,NOTIN,OR [,^ =,{,|,||, ,〜=。

我一直在抓我的頭,瀏覽網無濟於事,所以謝謝你的想法。

回答

1

這是SAS未能自動解除引用值的問題。我瞭解到的規則是,如果您的SAS代碼(由MPRINT顯示)看起來有效,但您遇到錯誤,請嘗試不加引號。

在你的情況下,更改爲:

%unquote(&&var&i.._num) = input(&&var&i,BEST16.); 

使代碼工作。當然,根據你的評論,你可能不需要%qscan這是引入有問題的引用字符。如果您將其更改爲%scan,則不需要%unquote()它,因爲它不會被首先引用。

也同意@Foxer的方法使用單個宏變量將i_th變量存儲在列表中。也會建議製作這些%局部變量以避免衝突。可能是這樣的:

%macro convert_car_to_num(input,output,listvar); 
    %local i vari; 

    data &output; 
    set &input; 
    %do i = 1 %to %sysfunc(countw(&listvar,%str())); 
     %let vari=%scan(&listvar,&i,%str()); 
     &vari._num=input(&vari,best16.); 
    %end; 
    run; 

%mend; 
+0

這正是我所尋找的解釋。我希望使用%qscan時要格外小心,以確保潛在的其他用戶不會與奇怪的名稱「混淆」,但我沒有完全意識到%qscan實際引用的含義,以避免任何意外的解決方案。 – Alan

+0

獨特的臨時變量的想法是一個很好的想法,但實際上我需要在循環之外的所有變量。至於做出一個獨特的循環: %do i = 1%to%sysfunc(countw(&listvar,%str())); 我確實認爲它好得多,但由於我可能與其他人共享這些宏,我更喜歡他們分解這些步驟,以免混淆人並使其更容易用於其他目的。 – Alan

+0

我仍然有一個詢問:如果我確實需要%qscan來避免不良分辨率,我仍然可以使用: %unquote(&& var&i .._ num) 我的猜測是否定的,因爲不加引用會導致潛在的不需要解析度。我錯了嗎 ?如果不是,我將如何處理? (真相被告知這是一個混亂的情況,我只是試圖完全理解宏的工作以及可用於防止意外結果的工具)。 不過,非常感謝您的第一個正確的答案 – Alan

0

下面給出你需要的東西嗎?我的猜測是,你有太多的事情在不同的if-then-do聲明:

%macro new(input,output,listvar); 
data &output; set &input; 
%do i=1 %to %sysfunc(countw(&listvar.)); 
    %let var=%scan(&listvar.,&i.); 
     var&i._num = input(&var.,BEST16.); 
%end; 
run; 
%mend; 

%new(have,want,&listvar.); 

下面也可以做你想做的,如果你想創建的每個變量中的單個宏變量你遍歷(雖然在這種情況下,它可能不值得,但只是顯示爲其他應用的另一個有用的方法):

** put variables into dataset **; 
proc sql noprint; 
    create table vars 
    as select name,type 
    from dictionary.columns 
    where upcase(libname)="WORK" and 
     upcase(memname)="HAVE" and 
     type = "char"; 
quit; 

** create total count and separate macro variable for each variable **; 
data _null_; set vars end=last; 
    by name; 
    i+1; 
    call symputx('name'||strip(put(i,8.)), name); 
     if last then call symputx('count',i); 
run; 

%put &count.; 
%put &name1.; 
%put &name2.; 
%put &name3.; 

** loop over each variable using the total count **; 
%macro new(input,output); 
data &output; set &input; 
%do i=1 %to &count.; 
    &&name&i.._num = input(&&name&i,BEST16.); 
%end; 
run; 

%mend; 

%new(have,want); 
+0

您的回答是正確的,因爲錯誤的來源是由%qscan func實現的引用,因爲%scan對我的直接需求工作得很好。您的簡短版本是我的目標是爲自己編寫,但由於各種原因(主要是我可能會共享代碼,並且我確實需要爲每個變量分別設置一個宏變量),我傾向於保留更長的時間,但對於其他用戶可能更清晰。 我打算看看你的sql版本,但在我看來,我不能選擇我想輸入哪些變量,這是我需要的核心(某些var在我的初始數據集中是正確的char)。 – Alan

+0

我可以找到方法,例如首先創建一個只包含我想輸入的var的數據集,但是我發現它無法使用即用型解決方案的目的。 不過,感謝所有的想法和評論 – Alan