宏[SAS]

时间:2015-08-05 23:05:12

标签: variables macros sas

所以,我想要一个内部有其他宏的宏。

这是代码:`

    proc sql NOPRINT ; 
        select id into :l_id separated by ' ' from work.AMOSTRACHU;
        select count(*) into :nr_reg separated by ' ' from tdata.work.AMOSTRACHU;
    quit;

    * check;
    %put l_id=&l_id nr_reg=&nr_reg;


    %macro ciclo_first();
    %do n=1 %to &nr_reg; 
    %let ref=%scan(&l_id,&n);
    %put ref=&ref;


    proc sql; 
    select recetor into : lsus&ref separated by ' ' from tdata.5pct_&ref;
    select count(*) into :nrsus&ref separated by ' ' from tdata.5pct_&ref;
    quit;

    %put lsus&ref=&lsus&ref;
    %put nrsus&ref=&nrsus&ref;

    %MACRO CICLO_PF_SUSref();
%do n=1 %to &nrsus&ref %by 1;
%let sus=%scan(&lsus&ref,&n);
%put sus=&sus;
%LET I = %EVAL(14);
%DO %WHILE (&I<=24);

*my code (depends on &i and &sus)* (works fine alone) 

%LET I = %EVAL(&I+1);

%END;
%END;
%MEND;
%CICLO_PF_SUSref;

%MACRO CICLO_PF_SUS_CSRANK();
%do n=1 %to &nrsus&refm %by 1;
%let sus=%scan(&lsus&ref,&n);
%put sus=&sus;

%CICLO_PF_SUSPEITOSrefmsisdn;

    %CICLO_PF_SUS_CSRANK;

我的代码(仅取决于&amp; sus) /

%END;
%MEND;
%CICLO_PF_SUS_CSRANK;

    %end;
    %mend;
    %ciclo_first;`

我认为主要问题在于这一部分:

%put lsus&ref=&lsus&ref;
    %put nrsus&ref=&nrsus&ref;

关于这个的错误是:

  

在%EVAL函数或%IF条件中找到了字符操作数   其中需要数字操作数。条件是:          &安培; nrsus&安培; REF

我怎样才能改变这个以便工作?据我所知,依赖于两个东西并不是很有意义,例如&amp; nrsus&amp; ref。

此处出现第一个警告和错误:

ref=15
WARNING: Apparent symbolic reference LSUS not resolved.
lsus15=&lsus15 WARNING: Apparent symbolic
reference NRSUS not resolved.
nrsus15=&nrsus15 ERROR: Expected semicolon not
found.  The macro will not be compiled.

我该如何解决这个问题?没有想法,为了避免这次运行100次,使这个宏起作用真的很有用。

更新[06.08.2015]

我有一个包含100个数字的表,就在

  

'work.amostrachu'。

我创建了宏ciclo_first,以便为此列表运行其他2个宏。因为,如果我用我想要的数字手动替换&ref它可以正常工作。

我们假设'work.amostrachu'有:

  

ID 1 2 3(...)直到n = 100

然后,用这部分:

 proc sql; 
         select recetor into : lsus&ref separated by ' ' from work.5pct_&ref;
         select count(*) into :nrsus&ref separated by ' ' from work.5pct_&ref;
         quit;

我想获取work.5pct_&ref

对于ID=1,我会获得lsus1,例如,3个数字(124,564,859)

然后,%MACRO CICLO_PF_SUSref();将输入这3个数字(可能是4或5或其他)。 (在这里,我可能会错误地称呼我想要的元素列表来自'work.5pct_&ref)。

然后,前一个宏的输出将是这一个的输入:%MACRO CICLO_PF_SUS_CSRANK。 这就是全部。

如果我只是用id替换%MACRO CICLO_PF_SUSref()%MACRO CICLO_PF_SUS_CSRANK&ref就可以了。这就是为什么我试图创建一个宏来运行这两个宏的初始列表。如果你有最好的想法,我会很感激。

所以,我想要的东西允许我为我在开头得到的列表运行这两个宏(%MACRO CICLO_PF_SUSref()和`%MACRO CICLO_PF_SUS_CSRANK):

 proc sql NOPRINT ; 
                select id into :l_id separated by ' ' from work.AMOSTRACHU;
                select count(*) into :nr_reg separated by ' ' from tdata.work.AMOSTRACHU;
            quit;

[更新10.08.2015]

好的,只需阅读建议的答案并进行处理。

我有一个列表,带有100个客户的标识(数字),让我们调用每个客户端:ref。这是在WORK.AMOSTRACHU。

我想了下面的代码并且它有效,并且会帮助我解释你想要的东西:

proc sql NOPRINT ; 
    select id into :l_id separated by ' ' from work.AMOSTRACHU;
    select count(*) into :nr_reg separated by ' ' from work.AMOSTRACHU;
quit;

* check;
%put l_id=&l_id nr_reg=&nr_reg;


%macro lista_ent();
%do n=1 %to &nr_reg; 
%put n=&n;
%let ref=%scan(&l_id,&n);
%put ref=&ref;

proc sql; 
select recetor into :listae&ref SEPARATED BY ' ' from work.e5pct_id&ref;
select count(*) into :nre&ref separated by ' ' from work.e5pct_id&ref;
quit;

%end;
%mend;
%lista_ent;

将显示前3个案例的输出(100个,work.amostrachu中的开始列表),这是SAS的结果部分:

Recetor 
507
723
955
-page break- 
3
-page break-
380
500
675
977
984
-page break-
5
-page break-
200
225
351
488
698
781
927
-page break-
7

所以,我有数据work.e5pct_id&amp; ref的列'recetor'的'值'以及每个ref有多少值。 (我已经向你展示了前3个参考的结果,但我已经为100了。)

现在,第一个宏:

%MACRO CICLO_M_PF_ref();
%local me n i;
%do n=1 %to nre&ref %by 1;
%let me=%scan(listae&ref,&n);
%put me=&me;
%LET I = %EVAL(14);
%DO %WHILE (&I<=24);

proc sql; 
create table work.smthng_&I as
select * from 
work.wtv&I
WHERE A=&me OR B=&me;RUN; 

PROC APPEND
DATA=work.smthng_&I
BASE=work.pf_&me
FORCE;
RUN; 


%LET I = %EVAL(&I+1);

%END;
%END;
%MEND;

%CICLO_M_PF_ref;

我对&amp; amp;和&amp;&amp;在这附近。

所以,对于数据:我有我的第一个参考,其中'recetor'列的结果是

Recetor 
    507
    723
    955
    -page break- 
    3

所以,我想为每个值运行该代码。首先是“507”,然后是“723”,然后是“955”,我想为所有裁判做到这一点。

因此,当宏完成运行我的代码3时,我希望宏跳转到第二个引用然后运行我的代码以获取第二个引用的列'recetor'的值:380,500,675,977和984。

我使用了这段代码:

 proc sql; 
    select recetor into :listae&ref SEPARATED BY ' ' from work.e5pct_id&ref;
    select count(*) into :nre&ref separated by ' ' from work.e5pct_id&ref;
    quit;

因为每个裁判都有不同的值,而且它们的数量可能不同,就像我给你看的那样。所以,这要告诉宏运行它nre&ref次以及列表listae&ref中的所有值。

错误如下:

  

错误:在%EVAL函数或%IF中找到了字符操作数   条件,其中需要数字操作数。条件是:          nre&amp; ref错误:%DO T循环的%TO值无效。错误:宏CICLO_M_PF_REF将停止执行。

2 个答案:

答案 0 :(得分:0)

我无法完全遵循您想要的输出和宏,但这里有一些我注意到的事情。

  1. 您的所有宏都没有参数。如果您更改宏以获取参数,则可以单独调用它们,这可能有助于简化流程。
  2. 我想你想要这样的东西:

    %macro def1(param1);
    ...
    %mend;
    
    %macro def2(param2);
    ...
    %mend;
    
    %macro execute();
    
    %do i=1 to 100;
       %def1(param1);
       %def2(param2);
    %end;
    %mend;
    

    这似乎有点尴尬,所以如果你能用你的数据来解释你的过程,那么整体可能会有更好的方法。

答案 1 :(得分:0)

我发现您可以解决许多问题,但如果没有测试数据则很难评估。

  • 当试图显示宏变量x&amp; i的值时,你需要加倍前缀&amp ;.因此,如果I = 1且X1 = FRED则&amp;&amp; x&amp; i = FRED。
  • 将值从SQL推入宏变量时,使用自动宏变量SQLOBS来获取记录计数。无需再次运行查询来获取计数。
  • 您无法在多个宏变量中选择COUNT(*)。 SQL只会返回一个计数。
  • SAS数据集或变量名称不能以数字(tdata.5pct_&amp; ref)开头或包含句点(tdata.work.AMOSTRACHU)。
  • 不要嵌套宏定义。您可以嵌套调用,但嵌套 这些定义只会导致混乱。

您的实际嵌套宏没有多大意义。引入的这个变量是什么?它似乎是一个常数。

为什么不将它们编码为外部宏的一部分?如果仅在一个地方调用它们,则不需要使它们成为单独的宏。

  • 如果嵌套它们,请确保将本地宏变量定义为local,以防止覆盖宏变量的值,这些宏变量的值与外部宏范围中可能存在的名称相同。例如,%DO循环的N循环变量。

首先定义子程序宏。

%MACRO CICLO_PF_SUSref(ref_list);
* CICLO_PF_SUSref ;
  %local n sus; 
  %do n=1 %to %sysfunc(countw(&ref_list,%str( )));
    %let sus=%scan(&ref_list,&n);
    %put NOTE: &sysmacroname N=&n SUS=&sus;
  %end;
%MEND CICLO_PF_SUSref;

%MACRO CICLO_PF_SUS_CSRANK(ref_list);
* CICLO_PF_SUS_CSRANK ;
  %local n sus ;
  %do n=1 %to %sysfunc(countw(&ref_list,%str( )));
    %let sus=%scan(&ref_list,&n);
    %put NOTE: &sysmacroname N=&n SUS=&sus;
    %put NOTE: Call macro named: CICLO_PF_SUSPEITOSrefmsisdn;
  %end;
%MEND CICLO_PF_SUS_CSRANK;

然后你的主宏。

%macro ciclo_first(id_list);
* Start ciclo_first ;
  %local n id ;
  %do n=1 %to %sysfunc(countw(&id_list,%str( ))); 
    %let id=%scan(&id_list,&n);
    proc sql noprint; 
        select recetor into : lsus&id separated by ' ' from pct_&id;
    %let nrsus&id = &sqlobs ;
    quit;
    %put NOTE: Current ID=&id ;
    %put NOTE: &&nrsus&id records read from PCT_&ID ;
    %put NOTE: Value List LSUS&id  = &&LSUS&id ;
    %CICLO_PF_SUSref(&&lsus&id);
    %CICLO_PF_SUS_CSRANK(&&lsus&id);
  %end;
* End ciclo_first ;
%mend ciclo_first;

然后设置一些数据并调用主宏。

* Setup test data ;
data AMOSTRACHU;
  do id=1 to 2; output; end;
run;
data PCT_1 ;
  do recetor='A','B';
    output;
  end;
run;
data PCT_2 ;
  do recetor='C','D';
    output;
  end;
run;

options mprint;
%ciclo_first(1 2);