如何扫描数字变量

时间:2015-07-11 00:08:08

标签: sas

我有一张这样的表:

 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&refwork.up&ref中引用。 我该怎么做?我做错了什么?

谢谢!

4 个答案:

答案 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。

  • runproc 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 ... ;