SAS:递归宏进入无限循环

时间:2016-05-10 14:16:01

标签: sas

有人可以解释为什么会这样吗? 我试图在数据库中查找对象依赖关系树。 让我们说view5是坐在顶视图4上的视图,它位于顶视图1上。 也, view3坐在顶部view2坐在顶部view1。 所以, 当我查询view1的宏时,我应该返回view4,view5,view2和view3。

这是宏:

%macro dependencies(obj=);
   %let dependent_objectname =;
   proc sql noprint;
      select  "'"||trim(dependent_objectname)||"'" 
        into :dependent_objectname separated by ", "
      from &_input.
      where src_objectname in (&obj.);
   quit;

   %put &dependent_objectname.;
   %let dependent_objectname = (&dependent_objectname.);
   %put &dependent_objectname.;

   %if %length("&dependent_objectname")>0 %then
      %dependencies(obj = &dependent_objectname.);
%mend dependencies;

%let source = 'ditemp.depend_test1';
%put &source.;
%dependencies(obj = &source.);

第一次迭代效果很好, 我让对象坐在上面depend_test1 以"(' ditemp.depend_test2',' ditemp.depend_test3')"的形式 然后我检查变量dependent_objectname的长度(大于零) 并再次调用宏, 只有它永远不会停止...

2 个答案:

答案 0 :(得分:2)

我看到了几个问题。

声明:

%if %length("&dependent_objectname")>0 %then %do;
即使& dependent_objectname的值为null,

也将始终返回true。因为引号是宏语言中值的一部分。你可能想要:

%if %length(&dependent_objectname)>0 %then %do;

对于零度的测试通常有效。或者参见本文以获得更好的方法。 http://support.sas.com/resources/papers/proceedings09/022-2009.pdf

在此之前,声明:

%let dependent_objectname = (&dependent_objectname.);

正在为您的值添加括号。所以,即使& dependent_objectname为null,在此之后也是()。看起来你不需要这些括号,所以我会跳过这句话。

我还想补充一下:

%local dependent_objectname ;

到宏的顶部。这样,每次调用宏都会有自己的本地宏变量,而不是让它们全部使用第一次迭代中创建的宏变量(或者更糟糕的是,都使用全局宏变量)。

您已明智地添加%PUT语句以帮助调试。我希望他们会证明& dependent_objectname的值总是非当前写的非null。您还可以添加:

%put The length is: %length(&dependent_objectname.) ;

答案 1 :(得分:2)

由于您使用SQL查询生成依赖列表,因此可以在测试中使用自动变量SQLOBS来中断递归。

%if &sqlobs %then %do;
    %dependencies(obj = &dependent_objectname.);
%end;

另外 NOT 使用逗号作为OBJ参数中列出的项之间的分隔符。 SAS中的IN运算符不需要它们,它们会在宏调用中造成麻烦。

select * from sashelp.class where name in ('Alfred' 'Alice') ;

所以你的宏看起来像这样:

%macro dependencies(object_list);
%local dependent_list ;
proc sql noprint;
  select catq('1as',dependent_objectname)
    into :dependent_list separated by ' '
    from &_input.
  where src_objectname in (&object_list)
    and dependent_objectname is not null
  ;
quit;
%put Dependent Objects of (&object_list) = (&dependent_list);
%if &sqlobs %then %dependencies(&dependent_list);
%mend dependencies;

这是一个测试用例。

%let _input=sample;
data sample;
  length src_objectname dependent_objectname $41 ;
  input (_all_) (:) ;
cards;
object1 object2
object2 object3
object2 object4
;;;;

%dependencies('object1');