Friday, November 20, 2015

IN operator

It is my favorite operator. Generally it is used to compare one expression on the left of the operator to a list of values on the right. However, you may find the two tricks are helpful.
#1. To search some variables, we have to use array.
data _null_;
    a=11;
    b=2;
    c=3;
    array vars a b c;
    /* if 1 in (a, b, c) then put "OK"; ERROR: we can not search the list of variables directly. */
    if 1 in vars then put "OK";
run;

#2. The modifier ":" can work well with IN operator.
data _null_;
    a='11';
    b='2';
    c='3';
    array vars a b c;
    if '1' in: vars then put "OK";
    if '111' in: vars then put "OK";
run;

Saturday, October 31, 2015

Customized buttons

I have created several customized buttons. Hopefully they are helpful.

Close ViewTable - next "viewtable:";end; next "viewtable:";end; next "viewtable:";end; next "viewtable:";end; next "viewtable:";end; wpgm
Submit Macro magic code - gsubmit "*'; *""; *); */; %mend; run;"; wpgm
New Save - file "d:\temp\saswork\%left(%sysfunc(datetime(), b8601dt.)).sas";
Open Work library location: gsubmit 'systask command "explorer %sysfunc(pathname(work))" nowait;'

Tuesday, August 18, 2015

Listing all files that are located in a specific directory (update)

I prefer the codes independent on OS. It may save a lot of time to maintain. Based on SAS Note 25074, I have created the codes at below:
%macro readdir(indir=, outdsn=);
    data &outdsn (keep=name infoname infoval);
       rc=filename("mydir", "&indir");
       did=dopen("mydir");

        if did > 0 then do;
            memcnt = dnum(did);
            do i=1 to memcnt;
                name = dread(did, i);
                
                rc = filename("myfile", catx("/", "&indir", name));
                fid = fopen("myfile");
                if fid > 0 then do;
                    infonum=foptnum(fid);
                    do j=1 to infonum;
                        infoname=foptname(fid, j);
                        infoval=finfo(fid, infoname);
                        output;
                    end;
                end;
                else do;
                    msg = sysmsg();
                    put msg;
                end;
                rc = fclose(fid);
            end;
        end;
        else do;
            msg=sysmsg();
            put msg;
        end;

        rc = dclose(did);
        rc = filename("mydir");
    run;
%mend;

%readdir(indir=C:\test, outdsn=out)

Friday, July 31, 2015

Code to Compare Data Strcuture

As I said in previous blog, we can compare the data structure using PROC COMPARE. Below is sample code.
data test;
    set sashelp.class; A=1;
    drop name;
run;

%macro comp(souce_dsn=, target_dsn=);
    proc compare base=&source_dsn(obs=0) comp=&target_dsn (obs=0) noprint;
    run;

    /*
    PROC COMPARE return code - SYSINFO:
        0400X Base data set has variable not in comparison 
        0800X Comparison data set has variable not in base  
        2000X Conflicting variable types
        0010X Variable has different length                     
    */
    %if %eval(%sysfunc(band(&sysinfo, 0400x)) = 0400x ) 
        or %eval(%sysfunc(band(&sysinfo, 0800X)) = 0800X ) 
        or %eval(%sysfunc(band(&sysinfo, 2000X)) = 2000X ) 
        or %eval(%sysfunc(band(&sysinfo, 0010X)) = 0010X ) 
    %then %do;
        %put ERROR: &source_dsn has different structure with &target_dsn;
    %end;
%mend;

%comp(souce_dsn=sashelp.class, target_dsn=work.test)

Wednesday, July 8, 2015

Compare the data structure using PROC COMPARE

PROC COMPARE is more useful than you think. It is mainly used to compare observations. And it is also a good tool to compare data structure. To compare only data structure, please exclude observation comparison using dataset option OBS=0.

Please see the code at below:
data test;
    set sashelp.class;
    drop name;
    test = 1;
run;

proc compare base=sashelp.class (obs=0) compare=test (obs=0) listvars; run;

Wednesday, March 4, 2015

run time analysis (with -TERMSTMT)

Some batches may take long time. You definitely do not want to wait until it finish. So when you kick off the batch, you can add the system option -TERMSTMT to run the program at below. For the tip -TERMSTMT, please see my previous post.
filename a temp;
filename mymail email "mail@address" subject="The job finished. Please check!";
options nonotes;
data _null_;
    file a;

    start_dttm = "&sysdate9 &systime"dt;
    end_dttm = datetime();
    run_time = end_dttm - start_dttm;

    run_minutes = intck('minute', start_dttm, end_dttm);
    if run_minutes > 15 then do;
        put "data _null_;";
        put "file mymail;";
        put "put 'Run time analysis:';";
        put "put '" "start time: " start_dttm datetime. "';";
        put "put '" "end time: " end_dttm datetime. "';";
        put "put '" "Run time: " run_time time5. "';";
        put "put '" "*** Run minutes ***: " run_minutes "';";
        put "run;";
    end;
run;

%inc a;

INITSTMT/TERMSTMT with %include

Here is scenario: You have to test many batches manually. As the jobs are for different projects, you want to setup environment at the beginning of SAS session, or send out analysis report at the end of SAS session. However, you can not change any existing configuration and program. Here I want to show how I handle them using system options INITSTMT/TERMSTMT.
$ alias sasp='/(saspath)/sas_batch.sh 
-initstmt "%let a=%sysfunc(quote(/work/scripts/initstmt.sas));%inc &a;" 
-termstmt "%let b=%sysfunc(quote(/work/scripts/termstmt.sas));%inc &b;" '

$ sasp code.sas -log code.(timestamp).log
Why I use "quote" function? As the shell may be confused with quotation.