Wednesday, October 18, 2017

Lookup using PROC FCMP data type dictionary

With 9.4M5, we will have one new technique - PROC FCMP dictionary. I wouldn't believe the new data type will be added in DATA STEP/DS2. We have to leverage the new data type via FCMP.
Below is sample code on how to lookup using the new technique.
proc fcmp outlib=work.funcs.test;
    subroutine s(a, b $, c $);
        outargs a, b;

        declare dictionary d;
        if c = 'add' then do;
            d[a] = b;
            d[b] = a;
        end;
        else if c = 'get_a' then do;
            a = d[b];
        end;
        else if c = 'get_b' then do;
            b = d[a];
        end;
    endsub;
run;

options cmplib=work.funcs;
data _null_;
    a = 1; b='xxx';
    call s(a, b, 'add');
    
    call missing(a);
    put "Note: get_a before " a= b=;
    call s(a, b, 'get_a');
    put "Note: get_a after " a= b=;

    call missing(b);
    put "Note: get_b before " a= b=;
    call s(a, b, 'get_b');
    put "Note: get_b after " a= b=;
run;

Output:
Note: get_a before a=. b=xxx
Note: get_a after a=1 b=xxx
Note: get_b before a=1 b=
Note: get_b after a=1 b=xxx

Tuesday, October 3, 2017

Easy way to check the file existence

SAS doc suggests "You can use SYSFILRC to confirm that a file or location is allocated before attempting to access an external file". I have not tested if it will work with special file but it works well with regular ones.

16   filename a "c:\";
17   %put &=sysfilrc;  /* file exists. */
SYSFILRC=0
18
19   filename b "c:\_not_exist";
20   %put &=sysfilrc; /* file does not exist. */
SYSFILRC=1

Saturday, September 23, 2017

Comma position in macro call

Comma is used to separate parameters in the macro call. We seldom care about the comma position.

For example:
%a(lib=a
, name=b)

%a(lib=a,
name=b)

Are the two macro calls identical? It may, or may not. If the code is deployed in LATIN1 but runs in UTF-8 session, it will have different result. In first call, the actual value of parameter LIB is "a(invisible carriage return)".

To make a general availability, please always put the comma just behind value in macro call.

Wednesday, September 6, 2017

Sample codes for SAS View

SAS has two kinds of views: SQL view and DATA view. They work similarly but we need to know what's the difference. Here, I give out some samples for clarification.
/* create DATA view */
data a / view=a;
    set sashelp.class;
run;

/* Create SQL view */
proc sql;
    create view b as
        select * from sasehlp.class;
quit;

/* Display Data view definition. 
Note: it can't be used for SQL view. */
data view=a;
    describe;
run;

/* Display SQL view definition. 
Note: it can't be used for DATA view. */
proc sql;
    describe view b;
quit;

/* There are 4 ways to delete views. 
 The last one is my favorite as it has most flexibility. */
proc delete data=work.a work.b (memtype=view); 
run;

proc sql;
    drop view work.a, work.b;
quit;

proc datasets lib=work nolist nowarn;
    delete a b / memtype = view;
run; quit;

proc datasets lib=work nolist nowarn memtype=(data view);
    delete a b;
run; quit;

Sunday, September 3, 2017

Check if dataset is locked.

Here is the tip to check if the dataset is locked by other PID. It is useful as it has write operation but actually does not change anything.
proc append base=dsn data=dsn(obs=0); run;

Friday, September 1, 2017

FINDW with null argument

Few SAS functions can take null argument. Definitely FINDW is special case. It means we can't use default delimiters when it is using modifier. Below is the sample codes and snippet from SAS documentation.
The FINDW function allows character arguments to be null. Null arguments are treated as character strings with a length of zero. Numeric arguments cannot be null.

data _null_;
    str = "aa bb";

    n1 = findw(str, "bb");  * Default deimilters are used;
    n2 = findw(str, "bb", ); * delimiter is NULL character;
    n3 = findw(str, "bb", ' '); * delimiter is blank character;
    n4 = findw(str, "bb", , 'E'); * delimiter is NULL character;
    n5 = findw(str, "bb", , 'SE'); * delimiter is space character, specified by 'S';
    put n1= n2= n3= n4= n5=;
run;

/* Output: n1=4 n2=0 n3=4 n4=0 n5=2*/

Tuesday, May 23, 2017

Update dataset compulsorily

NOTE: SAS set option OBS=0 and will continue to check statements. This may cause NOTE: No observations in data set.

Are you familiar with this note? It is common note when SAS run gets error. After the error, SAS macro can run, but it will not create/update any SAS dataset.
However, if you really want to change data, you can set two system options: OBS=MAX and NOSYNTAXCHECK.

Wednesday, March 29, 2017

CALL SET routine

I have dig the CALL SET routine and found two interesting points:
#1. In macro, it will resolve macro variable automatically. It means no leading ampersand is needed.
#2. In macro, it will link the dataset variable to closest macro variable that has same name. If the macro variable does not exist, it will create local one.

1    %macro setvar;
2        %local sex;
3       %let dsid=%sysfunc(open(sashelp.class, i));
4       %syscall set(dsid); /* No leading ampersand with %SYSCALL */
5
6       %put Note: Before fetchobs;
7       %put _local_;
8
9       %let rc=%sysfunc(fetchobs(&dsid, 10));
10      %let rc=%sysfunc(close(&dsid));
11
12      %put Note: After fetchobs, which will create local macro variable which does not exist.;
13      %put _local_;
14   %mend setvar;
15
16   %global name;
17   %setvar

Note: Before fetchobs
SETVAR DSID 1
SETVAR SEX

Note: After fetchobs, which will create local macro variable which does not exist.
SETVAR AGE 12
SETVAR DSID 1
SETVAR HEIGHT 59
SETVAR SEX M
SETVAR WEIGHT 99.5

18
19   %put _global_;
GLOBAL NAME John
GLOBAL RC 0

Monday, March 27, 2017

READONLY macro variable

READONLY macro variable is new feature of SAS 9.4. It can be defined as global or local like normal macro variable. However, it has different behaviors as follows:
1. As to global READONLY macro variable, it can not be changed or deleted once created.
2. Global READONLY macro variable is unique and can not be overlapped by local READONLY one.
3. The READONLY macro variable can not overwrite existing normal one

* Sample 1;
%global/readonly mv_ro=1;
%symdel mv_ro; /* ERROR: The variable MV_RO was declared READONLY and cannot be deleted */

* Sample 2;
%macro test;
    %local/readonly mv_ro=2; /* ERROR: The variable MV_RO was previously declared as READONLY and cannot be re-declared. */
%mend;
%test

* Sample 3;
%global mv;
%let mv=1;
%global/readonly mv=2; /* ERROR: The variable MV was previously declared and cannot be made READONLY. */

Thursday, March 16, 2017

Temporary file/folder

To use temporary file/folder, we can avoid leaving any legacy files in system. Here are my codes:
* SAS code to create temporary file;
filename a temp;
filename a list;

* SAS code to create temporary folder:
data _null_;
    guid=uuidgen();
    tmpdir=dcreate(guid,getoption('work'));
    call symputx('tmpdir',tmpdir);
run;

%put &=tmpdir;