2017-02-03 55 views
2

以下示例非常簡單,可以通過更簡單的方式解決。但是,我有興趣使其工作。以下示例基於sashelp庫的cars-dataset。首先,我有一個宏叫好玩:如何在更新宏變量並立即使用該值的數據步驟中調用宏?

proc contents data = sashelp.cars out = mycontents; 
run; 

%macro fun(var); 
proc sql noprint; 
     select count(distinct(&var.)) 
     into :obs 
     from sashelp.cars; 
quit; 
%mend; 

現在我想調用宏但只更新OBS(從輸入語句)。我用:

data work.test; 
set mycontents; 
if name ne "Type" then do; 
     call execute('%nrstr(%fun('||name||');'); 
     new = &obs; 
end; 
else new = 5; 

run;

總之,這應該迭代mycontents的行。然後根據名稱調用一個(幾個)宏,這會更新obs。然後,我可以簡單地使用obs填充新的列。但是,obs對所有名稱保持相同的值,這是來自最後一個變量的值。

+0

好問題,寫得很好! – Joe

+0

@Snorehorse(1)標題不需要說明它是一個SAS問題 - 標籤就是這樣做的。 (在google上,例如,標籤會隨着頁面一起出現。) – Joe

+0

(2)我不認爲'CALL EXECUTE'對於這個問題很重要;上面的標題有點寬泛,會有更多的點擊,而且'CALL EXECUTE'無論如何都會觸發這個帖子,因爲它在主體中。我會添加空間,你在那裏是正確的。 – Joe

回答

6

這裏的問題是雙重的。

首先,你不能在這種情況下使用CALL EXECUTE,因爲不執行,直到後的數據步驟完成運行:所以根據&obs東西將無法獲得一個更新的價值爲。你將不得不使用dosubl

其次,如果您想獲取中間數據步驟的更新值,則需要使用symget('obs')而不是&obs。編譯數據步驟時將解析&obs,因此在執行期間不能更改;但是symget(obs)指示數據步驟在執行期間查詢符號表。

下面是一個使用dosubl這樣做的例子,從你的例子中最小改變。請注意0​​聲明以確保obs在數據步驟中對我們可用(還有其他方法可以做到這一點以使其更好 - 即將此函數包裝在fcmp函數中並使用run_macro--但這最接近於你做吧)。

proc contents data = sashelp.cars out = mycontents; 
run; 

%macro fun(var); 
%global obs; 
proc sql noprint; 
     select count(distinct(&var.)) 
     into :obs 
     from sashelp.cars; 
quit; 
%mend; 

data work.test; 
set mycontents; 
if name ne "Type" then do; 
     rc = dosubl(cats('%fun(',name,')')); 
     new = symgetn('obs'); 
end; 
else new = 5; 
run; 
+0

@ Joe。非常感謝你幫助我。我對SAS很陌生,並沒有意識到這些功能。我一回到工作崗位就會嘗試。再次感謝! –

+1

沒問題,總是樂於幫助寫好問題! – Joe

+1

難道你不想使用symgetN,所以NEW會是數字嗎? –