SAS 中高效的宏循环以获取 Oracle 存储过程
Efficient macro looping in SAS to get to Oracle Stored Procedure
我正在使用 SAS 访问 Oracle 数据库。问题是函数/存储过程存在于 Oracle 中的一台服务器上——当我的数据也存在于那里时这很好——但是当数据在不同的服务器上时,我仍然想使用该函数。所以我用个人 id 加载了一些宏,将它们传递给循环中的函数。它有效,但速度非常慢。我不需要 'optimal',只需要 'reasonable'...我的数据集将最多包含 100,000 行。我读过创建数据集是 SAS 中资源最密集的工作之一,所以我正在尝试创建一个空的 table 并插入,但我还没有注意到有什么收获。
所以问题是 - 我可以在 SAS 中的合理时间内对不同服务器上的数据使用 Oracle 存储过程吗? (通过改进我现有的方法或完全不同的方法)
我的第一次尝试(13,000 个个人 ID 大约需要 25 分钟):
%MACRO STATE() ;
options nosource nonotes;
%* 2. get macro max loop n;
proc sql noprint;
select left(put(count(distinct pidm),10.)) into :loopn from examp
;quit;
%* 3. load macros with the pidms of interest;
proc sql noprint;
select distinct pidm into :pidm1 - :pidm&loopn from examp order by pidm;
quit;
%Do i = 1 %TO &loopn ; /*build em */
%* %put **************LOOP &i OF &loopn *********************;
proc sql noprint;
connect to oracle as mycon(user=xxxxxx password=xxxxxxx path='PROD') ;
create table subsetdat&i as
select * from connection to mycon
(select %quote(&&pidm&i) as pidm ,UILIB.ADDR.STATE(&&pidm&i, 'MA') as state
from dual);
disconnect from mycon ;
; quit;
%END;
data state; set subsetdat1-subsetdat&loopn ; /*stack 'em */
%Do j = 1 %TO &loopn ; /*drop 'em */
proc sql ;
drop table subsetdat&j
;
%END;
options source notes;
%MEND STATE ;
options nomprint;
%STATE() ;
移动到 proc sql
内部循环,从而消除从多个传递查询创建多个数据集的开销,并使用 union all
到 'stack' 单个查询结果.
%MACRO STATE() ;
options nosource nonotes;
/* 2. get macro max loop n; */
proc sql noprint;
select left(put(count(distinct pidm),10.)) into :loopn from examp
;quit;
/* 3. load macros with the pidms of interest; */
proc sql noprint;
select distinct pidm into :pidm1 - :pidm&loopn from examp order by pidm;
quit;
/* Build single pass-thru query with multiple select ... union all select ... etc */
proc sql noprint;
connect to oracle as mycon(user=xxxxxx password=xxxxxxx path='PROD') ;
create table state as
select * from connection to mycon
(%DO I = 1 %TO &loopn ; /*build em */
select %quote(&&pidm&i) as pidm ,UILIB.ADDR.STATE(&&pidm&i, 'MA') as state from dual
%IF &I lt &LOOPN %THEN %DO ; /* if not last iteration do a `union all` */
union all
%END ;
%END ;
) ;
disconnect from mycon ;
quit;
options source notes;
%MEND STATE ;
options nomprint;
%STATE() ;
我正在使用 SAS 访问 Oracle 数据库。问题是函数/存储过程存在于 Oracle 中的一台服务器上——当我的数据也存在于那里时这很好——但是当数据在不同的服务器上时,我仍然想使用该函数。所以我用个人 id 加载了一些宏,将它们传递给循环中的函数。它有效,但速度非常慢。我不需要 'optimal',只需要 'reasonable'...我的数据集将最多包含 100,000 行。我读过创建数据集是 SAS 中资源最密集的工作之一,所以我正在尝试创建一个空的 table 并插入,但我还没有注意到有什么收获。
所以问题是 - 我可以在 SAS 中的合理时间内对不同服务器上的数据使用 Oracle 存储过程吗? (通过改进我现有的方法或完全不同的方法)
我的第一次尝试(13,000 个个人 ID 大约需要 25 分钟):
%MACRO STATE() ;
options nosource nonotes;
%* 2. get macro max loop n;
proc sql noprint;
select left(put(count(distinct pidm),10.)) into :loopn from examp
;quit;
%* 3. load macros with the pidms of interest;
proc sql noprint;
select distinct pidm into :pidm1 - :pidm&loopn from examp order by pidm;
quit;
%Do i = 1 %TO &loopn ; /*build em */
%* %put **************LOOP &i OF &loopn *********************;
proc sql noprint;
connect to oracle as mycon(user=xxxxxx password=xxxxxxx path='PROD') ;
create table subsetdat&i as
select * from connection to mycon
(select %quote(&&pidm&i) as pidm ,UILIB.ADDR.STATE(&&pidm&i, 'MA') as state
from dual);
disconnect from mycon ;
; quit;
%END;
data state; set subsetdat1-subsetdat&loopn ; /*stack 'em */
%Do j = 1 %TO &loopn ; /*drop 'em */
proc sql ;
drop table subsetdat&j
;
%END;
options source notes;
%MEND STATE ;
options nomprint;
%STATE() ;
移动到 proc sql
内部循环,从而消除从多个传递查询创建多个数据集的开销,并使用 union all
到 'stack' 单个查询结果.
%MACRO STATE() ; options nosource nonotes; /* 2. get macro max loop n; */ proc sql noprint; select left(put(count(distinct pidm),10.)) into :loopn from examp ;quit; /* 3. load macros with the pidms of interest; */ proc sql noprint; select distinct pidm into :pidm1 - :pidm&loopn from examp order by pidm; quit; /* Build single pass-thru query with multiple select ... union all select ... etc */ proc sql noprint; connect to oracle as mycon(user=xxxxxx password=xxxxxxx path='PROD') ; create table state as select * from connection to mycon (%DO I = 1 %TO &loopn ; /*build em */ select %quote(&&pidm&i) as pidm ,UILIB.ADDR.STATE(&&pidm&i, 'MA') as state from dual %IF &I lt &LOOPN %THEN %DO ; /* if not last iteration do a `union all` */ union all %END ; %END ; ) ; disconnect from mycon ; quit; options source notes; %MEND STATE ; options nomprint; %STATE() ;