宏变量长度超过最大允许错误的解决方法

Solution to macro-variable length exceeding maximum allowed error

有一个 SAS 程序已经运行了一段时间,但我现在面临宏变量长度问题。我会尝试恢复程序的功能:

/* Buffing implicit macro-variable: */
proc sql noprint;
    select quote(trim(col))  into :implicit separated by " "
    from have
    where col contains "%";

/* Buffing valid_from macro-variable, format 16. to bypass 
   scientific notation */
proc sql noprint;
    select VALID_FROM format=16. into :valid_from separated by " "
    from have
    where col contains "%";

/* Buffing valid_to macro-variable, format 16. to bypass 
   scientific notation */
proc sql noprint;
    select VALID_TO format=16. into :valid_to separated by " "
    from have
    where col contains "%";
quit;

/* If &implicit. is not empty, then retrieve implicit col */
%if %sysevalf(%quote(&implicit.)=,boolean) = 0 %then %do;
    /* Loop on each col */
    %do i=1 %to %sysfunc(countw(&implicit.," "));
        /* Initializing the current expression, valid_from, valid_to */
        %let current_expression = %scan(&implicit.,&i.," ");
        %let current_valid_from = %scan(&valid_from.,&i.," ");
        %let current_valid_to = %scan(&valid_to.,&i.," ");

        %let _timer_start = %sysfunc(datetime());
        
        /* Retrieve current implicit col */
        /* And the corresponding valid_from and valid_to */
        data to_append;
            set BIG_TABLE
            (where=(upcase(col) like "&current_expression."));
            VALID_FROM = &current_valid_from.;
            VALID_TO = &current_valid_to.;
        run;
        
        /* End timer */
        data _null_;
            dur = datetime() - &_timer_start;
            put '<< Retrieved implicit col:' 
                "&current_expression." '. Time:' dur time13.2 ' >>';
        run;

    /* Append to the corresponding corporate_store */
    proc append base=want data=to_append;run;
    
    /* Delete append table */
    proc datasets lib=work nolist;delete to_append;quit;run;
    %end; /* End loop on each col */
%end;

/* If &implicit. macro-variable is empty, then there are no implicit col to retrieve */
%else %do;
    %put << No implicit col to retrieve... >>;
%end;

有关信息,&implicit. 宏变量如下所示:A[100][%][10] B[10][%][%] 目的是从 BIG_TABLE 获取所有符合类似条件的行,因此:A[100][10][10]A[100][20][10]、等等...

然而,今天 &implicit. 宏变量的长度超过了最大长度 (65534),我收到以下错误消息:

ERROR: The length of the value of the macro variable IMPLICIT (65540) exceeds the maximum length (65534). The value has been 
       truncated to 65534 characters. 

我在 上遇到了@Tom 的解决方案并决定重现它:

%let n_per_list=100;
/* Buffing &implicit. */
data _null_;
    length idlist 000;
    length macrolist 00;
    retain macrolist;

    do i=1 to &n_per_list. until (eof);
        set have(where=(col contains "%")) end=eof;
        idlist=catx(' ',idlist,quote(trim(col)));
    end;

    listno+1;
    call symputx(cats('implicit',listno),idlist);
    macrolist=catx(' ',macrolist,cats('&','implicit',listno));
    call symputx('implicit',macrolist);
run;

/* Buffing valid_from macro-variable, format 16. to bypass 
   scientific notation */
data _null_;
    length idlist 000;
    length macrolist 00;
    retain macrolist;

    do i=1 to &n_per_list. until (eof);
        set have(where=(col contains "%")) end=eof;
        format valid_from 16.;
        idlist=catx(' ',idlist,valid_from);
    end;

    listno+1;
    call symputx(cats('valid_from',listno),idlist);
    macrolist=catx(' ',macrolist,cats('&','valid_from',listno));
    call symputx('valid_from',macrolist);
run;

/* Buffing valid_to macro-variable, format 16. to bypass 
   scientific notation */
data _null_;
    length idlist 000;
    length macrolist 00;
    retain macrolist;

    do i=1 to &n_per_list. until (eof);
        set have(where=(col contains "%")) end=eof;
        format valid_to 16.;
        idlist=catx(' ',idlist,valid_to);
    end;

    listno+1;
    call symputx(cats('valid_to',listno),idlist);
    macrolist=catx(' ',macrolist,cats('&','valid_to',listno));
    call symputx('valid_to',macrolist);
run;

但我收到以下错误,因为它仍然将我的宏截断到允许的最大长度:

ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:

因此我想知道是否有绕过这个错误的技巧,或者是否有更有效的方法来做到这一点。我正在考虑使用哈希表进行查找,但我不确定它能处理类似的情况。

请注意 have 相当小(大约 3000 行)并且 BIG_TABLE 大约 8000 万行。

无需创建如此大的宏变量的一种方法是仅将数据保留在数据集中。

看起来您正在尝试对 HAVE 数据集中的每个观察做这样的事情。

%macro to_append(expression,valid_from,valid_to);

data to_append;
  set BIG_TABLE;
  where upcase(col) like &expression ;
  VALID_FROM = &valid_from.;
  VALID_TO = &valid_to.;
run;

%put << Retrieved implicit col: &expression
 %sysfunc(putn(%sysfunc(datetime())-&_timer_start,time13.2)) >> ; 

proc append base=want data=to_append force;
run;

%mend to_append; 

所以只需使用数据集为每个观察生成一个宏调用。也许通过使用 CALL EXECUTE().

data _null_;
  set have;
  call execute(cats
    ('%nrstr(%to_append)'
    ,'(',quote(trim(col),"'")
    ,',',valid_from
    ,',',valid_to
    ,')'
    )
  );
run;

或者将代码写入文件并%include。

filename code temp;
data _null_;
   set have;
   put '%to_append(' "'" col +(-1) "'," valid_from ',' valid_to ')';
run;
%include code / source2;

注意:在宏调用中包含 COL 值周围的单引号将阻止宏处理器尝试解释 % 字符.

还有“宏数组”的方法。我个人认为这种方法不值得付出努力,因为直接使用数据更容易。这个想法是创建 N 个单独的宏变量,而不是将 N 个值连接到一个宏变量中。

proc sql noprint;
  select quote(trim(col),"'"), valid_from, valid_to
    into :expression1-,:valid_from1-,:valid_to1-
    from have
  ;
%let n=&sqlobs;
quit;

%do i=1 %to &n ;

data to_append;
  set BIG_TABLE;
  where upcase(col) like &&expression&i ;
  VALID_FROM = &&valid_from&i;
  VALID_TO = &&valid_to&i;
run;
...
%end ;