高效地停止大型 SAS 程序

Halting Large SAS Program Efficiently

我有一个非常大的 SAS 程序,包含大约 50 个子程序,每个子程序都有很多步骤。此时无论是否有错误都会运行直到完成。但是,我要求它在发生错误时停止并退出。

请注意(我相信)SYSERR 宏不适合此任务,因为我需要在每个单独步骤的末尾检查 SYSERR(例如,在每个 DATA 或 PROC 步骤之后),因为 SYSERR 在每个步骤后重置台阶边界;这将是一项非常耗时且容易出错的任务,因为在我的 50 个子程序中,每个子程序都有数千个不同的步骤边界。

我设想的解决方案包括检查每个(50 个)子程序生成的日志文件 运行,然后如果日志文件中出现错误则停止(如果没有错误则继续下一个子程序)。但是,我无法想象如何做到这一点。 非常感谢。

我相信你检查日志的解决方案是好的。 因为您可以过滤 "WARNING" 和 "ERROR" 或 "ERROR:" 等词的日志。 您可以将过去的日志复制到 excel 并过滤是否包含这些错误关键字的行。

不过,我这里有 SAS 的解决方案,

1) 使用 proc printto 创建日志 2) 关闭 proc printto 重定向 3)用SAS自动分析日志

宏函数的代码如下:

/**
*
* @dev Function to create a log for a program
* @param job The name of the job to be logged
*
*/

%macro runjob(job /*Enter the name of the job to log Ex: myjob*/);
    option fullstimer;

    %let runjob=%sysfunc(compress(&job._%sysfunc(datetime(),b8601dt)));
    data _null_;
        call symputx("runjob","&runjob.",'G');
    run;

    filename logfile "C:\LOG\&runjob..log";

    proc printto log=logfile new;
    run;

%mend runjob; /* %runjob(myjob); */


/**
*
* @dev Funtion to check if a table is empty
* @param inset The name of dataset to be checked
*
*/

%macro checkTableIfEmpty(inset /* Write the name of your dataset (ex: checklog) */);
    %let dsid = %sysfunc (open(&inset));


    %if &dsid ge 0 %then
        %let dsid = 1;
    %let anyobs = %sysfunc (attrn(&dsid,ANY));
    %let dsid = %sysfunc (close(&dsid));

    %put anyobs=&anyobs;

    %if &anyobs = 1 %then
        %do;

            data _null_;
                call symputx('checkTableIfEmpty',0,'G');
            run;

        %end;
    %else
        %do;

            data _null_;
                call symputx('checkTableIfEmpty',1,'G');
            run;

        %end;
%mend checkTableIfEmpty; /* %checkTableIfEmpty(checklog); */


/**
*
* @dev Function to filter a log file from SAS with words like "warning" and "error"
* @param inp The pathname of the log to be checked
*
*/

%macro checkLog(inp /* Write the pathname of the log to be checked (ex: myjob_20170818T161545.log) */);

    data empty_marker;
        length MSG 0;
        MSG='No error(s)/warning(s).';
    run;

    DATA CHECKLOG;
        LENGTH ROWS 0;
        LABEL ROWS = 'Messages from LOG';
        INFILE "&inp" TRUNCOVER;
        INPUT ROWS &;
        LINE = _N_;

        IF SUBSTR(ROWS,1,5)='ERROR' OR SUBSTR(ROWS,1,7)='WARNING' THEN
            OUTPUT;
    RUN;

    %checkTableIfEmpty(checklog);

    ODS HTML BODY="C:\LOG\log.html" STYLE=sasweb;
    TITLE1 "Messages from LOG";

    %if &checkTableIfEmpty = 0 %then
        %do;
            proc sql;
                select distinct(rows) from checklog;
            run;

        %end;
    %else
        %do;

            proc print data=empty_marker;
            run;

        %end;

    ODS HTML CLOSE;
%mend checkLog; /*  %checkLog(c:\LOG\myjob_20170818T161545.log);  */

然后您可以在这样的程序中使用这些函数

%let jobname=myjob;
/* START */
%runjob(&jobname);

...

/*END*/
proc printto;
run;

%checkLog(C:\LOG\&runjob..log);

你会在 C:\LOG\LOG.html

中得到一个 html 文件
Messages from LOG
ERROR: Ambiguous reference, column DateSent is in more than one table. 
ERROR: Ambiguous reference, column Operation_date is in more than one table. 
ERROR: Expression using equals (=) has components that are of different data types. 
ERROR: Expression using less than or equal (<=) has components that are of different data types. 

由于 "distinct" 选择,重复的行被删除。 有了每个子程序的每个日志,调试起来真的会更容易。

此致,