我有一张这样的表:
Lista_ID 1 4 7 10 ...
总共有100个数字。
我想将这些数字中的每一个称为我创建的宏。我试图使用' scan'但请注意它只是用于字符变量。 我运行以下代码时的错误是
代码:
proc sql;
select ID INTO: LISTA_ID SEPARATED BY '*' from
WORK.AMOSTRA;
run;
PROC SQL;
SELECT COUNT(*) INTO: NR SEPARATED BY '*' FROM
WORK.AMOSTRA;
RUN;
%MACRO CICLO_teste();
%LET LIM_MSISDN = %EVAL(NR);
%LET I = %EVAL(1);
%DO %WHILE (&I<= &LIM_MSISDN);
%LET REF = %SCAN(LISTA_ID,&I,,'*');
DATA WORK.UP&REF;
SET WORK.BASE&REF;
FORMAT PERC_ACUM 9.3;
IF FIRST.ID_CLIENTE THEN PERC_ACUM=0;
PERC_ACUM+PERC;
RUN;
%LET I = %EVAL(&I+1);
%END;
%MEND;
%CICLO_TESTE;
错误是:
VARIABLE PERC是UNITIALIZED和
VARIABLE FIRST.ID_CLIENTE是UNITIALIZED。
我想要的是为之前显示的列表中的每个ID运行此宏,并在work.base&ref
和work.up&ref
中引用。
我该怎么做?我做错了什么?
谢谢!
答案 0 :(得分:1)
这是CALL EXECUTE
版本。
%MACRO CICLO_teste(REF);
DATA WORK.UP&REF;
SET WORK.BASE&REF;
BY ID_CLIENTE;
FORMAT PERC_ACUM 9.3;
IF FIRST.ID_CLIENTE THEN PERC_ACUM=0;
PERC_ACUM+PERC;
RUN;
%CICLO_TESTE;
DATA _NULL_;
SET amostra;
*CREATE YOUR MACRO CALL;
STR = CATT('%CLIO_TESTE(', ID, ')');
CALL EXECUTE(STR);
RUN;
答案 1 :(得分:0)
首先你要注意SAS宏变量解析本质上是一个基于文本的&#34;&#34;复制粘贴动作。也就是说,所有用户定义的宏变量都是文本。因此,在这种情况下,%eval
是不必要的。
其他杂项更正包括:
检查%scan()
功能是否正确使用。第一个参数应该是一个文本字符串WITHOUT QUOTES。
run
在proc sql
中是多余的,因为每个sql语句在发送后立即运行。使用quit;
退出proc sql。
宏调用不需要分号(有时会导致意外问题)。
使用%do %to
for循环
以下代码应该有效。
data work.amostra;
input id;
cards;
1
4
7
10
;
run;
proc sql noprint;
select id into :lista_id separated by ' ' from work.amostra;
select count(*) into :nr separated by ' ' from work.amostra;
quit;
* check;
%put lista_id=&lista_id nr=&nr;
%macro ciclo_teste();
%local ref;
%do i = 1 %to &nr;
%let ref = %scan(&lista_id, &i);
%*check;
%put ref = &ref;
/* your task below */
/* data work.up&ref;*/
/* set work.base&ref;*/
/* format perc_acum 9.3;*/
/* if first.id_cliente then perc_acum=0;*/
/* perc_acum + perc;*/
/* run; */
%end;
%mend;
%ciclo_teste()
在SAS 9.4 win7 x64上测试
编辑:
实际上我建议这样做是为了避免扫描效率低的长字符串。
%macro tester();
/* get the number of obs (a more efficient way) */
%local NN;
proc sql noprint;
select nobs into :NN
from dictionary.tables
where upcase(libname) = 'WORK'
and upcase(memname) = 'AMOSTRA';
quit;
/* assign &ref by random access */
%do i = 1 %to &NN;
data _null_;
a = &i;
set work.amostra point=a;
call symputx('ref',id,'L');
stop;
run;
%*check;
%put ref = &ref;
/* your task below */
%end;
%mend;
%tester()
如果您还有其他问题,请与我们联系。
答案 2 :(得分:0)
data work.amostra;
input id;
cards;
1
4
7
10
;
run;
%macro test001;
proc sql noprint;
select count(*) into: cnt
from amostra;
quit;
%let cnt = &cnt;
proc sql noprint;
select id into: x1 - :x&cnt
from amostra;
quit;
%do i = 1 %to &cnt;
%let x&i = &&x&i;
%put &&x&i;
%end;
%mend test001;
%test001;
现在变量&amp; x1 - &amp;&amp; x&amp; cnt你有你的价值,你可以随意处理它们。
答案 3 :(得分:0)
一般来说,如果您的列表足够小(宏变量限制为64K字符),那么最好将列表传递给单个分隔的宏变量而不是多个宏变量。记住PROC SQL会自动将计数设置为宏变量SQLOBS因此不需要运行两次查询。或者,您可以使用%sysfunc(countw())来计算分隔列表中的条目数。
proc sql noprint ;
select id into :idlist separated by '|' from .... ;
%let nr=&sqlobs;
quit;
...
%do i=1 %to &nr ;
%let id=%scan(&idlist,&i,|);
data up&id ;
...
%end;
如果确实生成了多个宏变量,则无需事先设置上限,因为SAS只会根据查询返回的观察数创建所需的宏变量数。
select id into :idval1 - from ... ;
%let nr=&sqlobs;
如果您使用的是较旧版本的SAS,则需要在宏变量范围上设置上限。
select id into :idval1 - :idval99999 from ... ;