Monday, November 26, 2012

Command line arguments in SAS / SAS System Options

Most often than not, we tend to run the SAS program in command lines. If the SAS is present in UNIX, we open a client terminal like PuTTY or SSH terminal and invoke the SAS program. If the SAS is present in Windows, then we can do the same by opening command mode.

The sytax for invoking the SAS Program is as follows:

sas <path and program-name>.sas

We need to make sure that the path of sas executable is present in the PATH enviroinment variable.

What is more interesting are the other command line arguments that we can pass while invoking a SAS program as mentioned above in the command line. Below, I've tried to illustrate each of them with the sytax and usage detail:

  • SYSPARM: This is the most useful option that I have come across. This lets us send parameters to the SAS programs through the command line prompt. The value of the SYSPARM is saved under the macro variable- SYSPARM, which can be accessed within the program. For Example, the below code - class.sas lets us send the age as a parameter while invoking the SAS Program.
     %put &sysparm;

     proc print data=sashelp.class noobs;
     where age=&sysparm.;
     run;

           We can invoke the SAS program in the command mode as follows:

           sas class.sas -sysparm "14"

    One can even send a list of key-value pair values through the program which will feed-in to a macro.
  • LOG: This option would redirect the log file to the specified location instead of the default location.
          Usage:     sas class.sas -log "~/temp.log"
  • WORK: This would help us specify the work directory location instead of the default work place.
I also found that SAS 9.3 has come up with new options to use Checkpoint Mode and Restart Mode for Labeled Code Sections if the program has terminated in the middle and if we need to restart it from a specific point onwards. More to come in this in the next post!

Let me know your thoughts!

Saturday, April 9, 2011

Creating a search engine in SAS

Its the age of the search engine! I remember people "yahoo"ing during the late 90's and "Google"ing till the late 2k's and now "Bing"ing.

I just wondered.. Why not SAS? So I started off by doing some reading on the yahoo search engine API's. They have new API released, called as the BOSS. Its documentation is provided here: http://developer.yahoo.com/search/boss/boss_guide/

Next step was to fetch a api key which was generated after i filled out their form. Using this, i could start accessing their BOSS api...

I used the proc http to access the BOSS api using the program below:

filename in "C:\test\curr_in";
filename out "C:\test\curr_out.txt";


data _null_;
title;
if (_N_ eq 1) then do;
 file stdout;
 infile stdin;
 put @1 "Enter the search text:";
 input n $;
 var='appid=xxxxxxx&query='||compress(n)||'&results=1';
 file in;
 put var $;
end;
run;



proc http in=in out=out url="http://search.yahooapis.com/WebSearchService/V1/webSearch" method="post" ct="application/x-www-form-urlencoded";
run;

The above program picks the input from the user, which would be the text that needs to be searched; creates a file curr_in which contains the parameter that needs to be sent out to the BOSS api and posts it to the api using the proc http procedure.

Note that the api key has been typed as xxxx which can be replaced by the api key that you would generate from the developer.yahoo.com site.

Once the program is executed, we can see that the output of the api has been dumped into the curr_out file, which contains the search result in the form of XML. This xml is then parsed using the suitable mechanism to fetch the needed fields and then output it to the stdout. This is accomplished by the below code:

data new;
infile out lrecl=10000 truncover;
input @1 rec $1000.;
if(index(rec,'<Summary>')>0) then do;
 title= substr(rec,index(rec,'<Title>')+7,index(rec,'</Title>')-(index(rec,'<Title>')+7));
 summary=substr(rec,index(rec,'<Summary>')+9,index(rec,'</Summary>')-(index(rec,'<Summary>')+9));
 url = substr(rec,index(rec,'<Url>')+5,index(rec,'</Url>')-(index(rec,'<Url>')+5));
 output;
end;
run;

data _null_;
set new;
file stdout;
put "Title: " title;
put "Summary: " summary;
put "Url: " url;
run;


This produces the output as shown below:


Let me know your feedback/comments!

Sunday, March 20, 2011

Using SAS as my makeshift alarm: Using sound function

I have trouble waking up early everyday. And the days when i forget to set alarm in my mobile, I might wake up two days later!!

I've overcome this problem after i discovered this the sound function in SAS. This function produces a beep sound for the specified frequency and time which are to be supplied as the arguments.

Now, lets see how we make the conventional alarm sound which would ring for 20 times:

data _null_;
do j=1 to 20;
   do i=1 to 4;
      sound(550,500);
   end;
   sleep(1000);
end;
run;

Now, if we schedule this code in a windows scheduler to run everyday at some designated time, SAS would take up the task of waking you up everyday.

I use this sound function more often at the end of my long running programs. It would beep after the completion of the program (yes.. pretty similar to the oven) so that we could do the needful actions.

Just to note that this is possible only with the Windows SAS and the sound function does not work in UNIX/Mainframes.

I would like to end this post by sharing with you, a brilliant application of this sound/sleep function: the composition of the "Ol Mac Donald" Song:

http://www2.sas.com/proceedings/sugi29/048-29.pdf

So.. Let the music begin!!!

Saturday, March 19, 2011

SASopedia gets a face lift

I know it was high time I did it... Hope this is more viewable...

Watch out for more posts in this space...

Sunday, March 6, 2011

Making SAS Interactive (Part 2): Using %window and %display

Its the world of GUI. And you are left nowhere if you don't provide the users, the luxury (or rather fulfill the basic needs) of giving a Graphical User Interface. This holds good even for SAS.

SAS came up with the tool called SAS/AF and SAS EG which provides the users with a brilliant GUI and thus making their lives so eeaasssy.. However, not many of us would have bumped into this brilliant macro tool called %WINDOW and %DISPLAY which is present in BASE SAS9 which satisfies the basic needs of having a GUI. Here I take a small dive into the SAS ocean again, exploring the functionalities of these two macros.

%WINDOW: This creates the basic window that needs to be popped up upon execution. We can specify the window attributes here like the color/width/height,etc. You could also specify the position of the text that is to be displayed and the input parameters that are to be read.

%DISPLAY: This actually invokes the window that has been defined in the %window program.

Below is a simple illustration of the %window and %display invocation:

%window test_win color=blue

/*dimension for the window*/
icolumn=15 irow=10
columns=90 rows=45


/*Content of the window*/
#3 @25 "My Window"
attr = rev_video
#5 @10 "Hello Pramod"
attr = underline
;


%display test_win;

The above code displays the output as shown below:



Below, I've demonstrated how we can use this to make SAS interactive. Most of the code is self explanatory, of course with a bit of help from the support.sas.com documentation available at: http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/viewer.htm#a000206734.htm

/* Main window */

%window final color=gray

/*dimension for the window*/
icolumn=15 irow=10
columns=90 rows=75


/*Content of the window*/
#1 @25 "&error_msg"
#3 @15 "Hi &sysuserid." attr = rev_video color=blue @60 "Date: &sysdate9." attr = rev_video color=blue
#5 @25 "Welcome to the Reporting World" attr = rev_video

#8 @35 "Report List"
#11 @15 "1. Class listing" @50 "2. Class Report by Gender"
#13 @15 "3. Class Report by Age" @50 "4. Class freq"
#16 @15 "Enter your Choice:" @35 choice attr=underline
;


/* End of Window Final */

%macro execute;
%let choice=;%display final;

%if &choice=1 %then %do;
 proc print data=sashelp.class noobs;
 run;
%end;
%else %if &choice=2 %then %do;
 proc report data=sashelp.class nowd;
 columns sex height weight;
 define sex / group;
 define height /analysis;
 define weight / analysis;
 run;
%end;
%else %if &choice=3 %then %do;
 proc report data=sashelp.class nowd;
 columns age height weight;
 define age / group;
 define height /analysis;
 define weight / analysis;
 run;
%end;
%else %if &choice=4 %then %do;
 proc freq data=sashelp.class;
 tables sex*age /nocum nopercent;
 run;
%end;
%mend execute;

%execute
In the above code, I first display a list of things the use might be interested to see in the %window, and then %display this inside the macro execute. I also read his input into the macro variable choice and then based on his selection, I call the required procedure inside the macro execute.

The output of the above code is as shown below:


Upon entering the value 2 and hitting the enter button, we get the output as shown:




You could experiment more on this and let me know your suggestions/thoughts/ideas...

Monday, February 28, 2011

Making SAS Interactive (Part 1): Using stdin and stdout

Many a times, we may come across a need for having a dynamic programs. Meaning, we may need the user to key in the input and run the code accordingly, based on his input. This can be achieved in SAS by using the automatic file descriptors: stdin and stdout. This is more widely used in UNIX environment, especially when we batch submit the code in the command line.

In the below code, I illustrate the use of stdin and stdout by implementing a simple calculator, which takes in the numbers and the operators as the arguments and outputs the results.

data test;
if (_N_ eq 1) then do;
 file stdout;
 infile stdin;
 put @1 "Enter the first variable:";
 input X @;
 put @1 "Enter the second variable:";
 input Y @;
 put @1 "Choose the operator: + - * / **:";
 input op $;
end;
retain X Y op;
select (op);
 when ('+') result=X+Y;
 when ('-') result=X-Y;
 when ('*') result=X*Y;
 when ('/') result=X/Y;
 when ('**') result=X**Y;
 otherwise ;
end;
put "The result is:" result;
run;


In the above code, I've redirected the infile and file statements to the stdin and stdout respectively. So the input is always read through the terminal key and the output is always written to the terminal.

When we run the above code in the batch mode, we get the following output:


We can also route the output of a procedure into the terminal using the proc printo as shown below:

proc printto print=stdout;
run;


The below code would output all the details of the student whose name is keyed in the terminal for the sashelp.class dataset:

data name;
title;
if (_N_ eq 1) then do;
 file stdout;
 infile stdin;
 put @1 "Enter the student name:";
 input n $;
end;
retain n;
call symput('name',n);
run;

proc printto print=stdout;
run;
options nodate nonumber;
proc print data=sashelp.class noobs;
where name="&name";
run;


This would give us the below output:



Let me know if you guys have any thoughts or other approaches.

More to come: Making SAS Iinteractive (Part 2): Using window prompts

Saturday, February 19, 2011

Reading a table from a website into a SAS dataset

Many a times we may want to read a table from the webpages into our datasets. This may be a requirement especially when I would want to analyse the stock market shares and their corresponding trends over the past. This can be done in many ways depending on the web application that is in consideration.

Here I discuss the filename url and the other related methods to access the static webpage which we see in the browser. However, there are many other different methods like FTPing the webpage through some mechanism and then parsing the html/aspx source tags to get the required data, etc.

Now that the Cricket world cup is here, i've decided to use the http://www.espncricinfo.com/ to show how we can read the scorecard into our datasets. I've used a match score card which appears like this in the website:



To begin with, we need to assign a filename to the url where the table resides, by using the filename url syntax:

filename fn url "http://www.espncricinfo.com/icc_cricket_worldcup2011/engine/match/473333.html";

Now that the fileref has been added, we try reading the file into the dataset using the infile/input statements in a datastep:

data _null_;
infile fn lrecl=30000;;
input col1 $10000.;
file "~/test.txt";
put col1 $10000.;
run;

Note: The default value for the lrecl (where we specify the maximum record length in the file), is 256 characters. However, one can specify a value upto 32767. I've specified a length of 30000 just assuming that the html file max length would be 30000.

The above code reads one entire line from the url specified (which essentially contains a html file) into the SAS as a single character variable of length 1000 and writes it into a file named test.txt.

When we open the test.txt to read the contents of the html, we see a lot of html tags which needs to be parsed into a dataset to get the table of our choice.

In the test.txt, we see the following tags appearing in the file as shown below :

<td width="192"><a class="playerName" href="http://www.blogger.com/icc_cricket_worldcup2011/content/player/35263.html" target="" title="view the player profile for Virender Sehwag">V Sehwag </a>&nbsp; </td>

<td class="battingRuns">23</td>

<td class="battingDetails">30</td>

<td class="battingDetails">0</td>

Now, all we need to do is look out for the occurrences of  the text tag: 'class="playerName"' to fetch the player name; 'class="battingRuns">' to fetch the player score; 'class="battingDetails">' to fetch the player matches, and so on and so forth..

This can easily be done by using the following data step code:

data inp;
infile "~/test.txt" lrecl=30000;
input @'class="playerName"' name1 $300. @'class="battingRuns">' runs1 : $20. @'class="battingDetails">' matches1 : $20.;
run;


The above code searches for the occurrences of the text 'class="playerName"' and reads 300 characters following it into the variable name1. Similarly, it also searches for the occurrence of the text 'class="battingRuns"' and 'class="battingDetails"' and reads upto the next 20 characters until it encounters a space (the default delimiter).

Now the first observation of the dataset inp contains the following values:


Name1
Runs1
Matches1
href="http://www.blogger.com/icc_cricket_worldcup2011/content/player/35263.html" target="" title="view the player profile for Virender Sehwag">V Sehwag </a>&nbsp; </td>
23</td>
30</td>


Now, we need to extract the name (V Sehwag) from the name1 variable. This can be done by picking the index of </a> and the string '">' from the value of the variable name1. The function is as follows:

x=index(t,'</a>');
y=index(t,'playerName');
name=substr(t,x+4,y-x+4);


The above set of functions calculate the x and y indices which is the beginning point and the ending point of the string V Sehwag. Then i do a substr of the string knowing the beginning position and the ending position.

To extract the numeric value from the character value, we use the following function:

runs=input(compress(lowcase(runs1),'abcdefghijklmnopqrstuvwxyz<>/'),8.);

Now, coming all the above set of functions, a data step can be built which would give us the final set of data as follows:

data final;
set inp;
x=index(name1,'</a>');
y=index(name1,'playerName');
name=substr(name1,x+4,y-x+4);

runs=input(compress(lowcase(runs1),'abcdefghijklmnopqrstuvwxyz<>/'),8.);
matches=input(compress(lowcase(matches1),'abcdefghijklmnopqrstuvwxyz<>/'),8.);
run;

Thats it for now.. Let me know your experiences or suggestions on doing this in a better way...

Monday, January 31, 2011

Dark Secrets of %sysfunc

I've been using the %sysfunc for quite sometime now. I must say that its a pretty handy tool.. Especially when you would want to do some heavy wieght lifting in macros. However, one must be mindful of the following... (can I say shortcomings?? Naa.. not quite...)


Quoting fails in %sysfunc:

It is starkly visible when you try using intnx function in a macro. For example, you would want to build a month incrementor in a loop. You would do something like this:

%macro doit;
%let dt='01JAN2011'd;
%do i=1 %to 12;
%put mon=%sysfunc(month(%sysfunc(intnx('month',&dt,&i))));
%end;
%mend doit;

%doit

(Note: We usually do not need a semi-colon (;) after invoking a macro.. But habits die-hard. I'm trying my best to aviod it..)

The above code fails to run as expected. %sysfunc throws up tantrums saying:

WARNING: An argument to the function INTNX referenced by the %SYSFUNC or %QSYSFUNC macro function is out of range.

This is purely because the %sysfunc does not like the quotes around the month inside the intnx function. Just remove them and SAS becomes your ever-loyal-man Friday!

Some basic funnctions like put and input doesn't work!!

I was taken aback when i discovered this. (Ya.. I know... I know that i din do my documentation reading properly when i was asked to..)

When I submit this program inside a macro,

%put %sysfunc(put('31Jan2011'd,worddate.));

SAS slaps me with this error message:

ERROR: The PUT function referenced in the %SYSFUNC or %QSYSFUNC macro function is not found.

But this is unexpected... Now.. How on the earth am i supposed to do the type casting which is an integral part of my life (of course apart from my wife!!)

SAS says that you should be using putn, putc, inputn and inputc instead of the regular put/input functions for numeric/charater variables respectively. Wow.. Problem solved!!!The above code can now be written as:

%put %sysfunc(putn('31Jan2011'd,worddate.));

%Sysfunc can be used with a format specifyer (similar to the put function)

This was one of those 'learnings' I had from my SAS Advanced Certification perparation. %sysfunc could be used along with a format speicifer (thus avoiding the necessity to have put function).

The above function can be further reduced as given beow:

%put %sysfunc(today(),worddate.);

So much for now.. Please let me know your thoughts on this or if you have found anything more interesting to do with the %sysfunc

Saturday, January 29, 2011

Am back!!

Hey Guys... I know this blog was asleep for a month or so without any activity.. I owe it to my Advanced SAS Certification preparaion...

And I got Certified!!!!

Now that I'm back.. You can expect more posts on the new things that i found out while preparing for the certification!

Cheers!!

Tuesday, December 28, 2010

Send Seasons Greetings - in SAS

On this festive season, you can send cool animated images to your loved ones - a la SAS way!!! Here is how you do it.
  • Add a filename email with the required to/cc/bcc id's.
  • Include the HTML img tag and give the following source path as shown below.
  • You can also hyperlink it to your website if you might want to...

FILENAME mail1 EMAIL
TO=("getpramod.r@tgmail.com" )
From =("getpramod.r@gmail.com")
SUBJECT ="Season's Greetings"
type="text/html"
CT= "text/html" ;


DATA _NULL_;
FILE mail1;
PUT ' Wish You a Merry Chirstmas!!! ';
PUT 'https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCaGnPq1eSjeP0gsO1yQ7PS2xrmQhMkhtPWcJfN5QaF5lHMJA93CEEGuxT-d9yK0UWMb5ndTTrx-W8eTKZX-UWxWmWFtqsTThpmTH1LZZ7LdWwQrfbzGI44clJ701r6BYJqq5kU739GjiM/s320/merry_christmas_animated.gif';
PUT 'And a Happy New Year!!! ';
PUT 'https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbP_vaGfAyMMH-BzhNgPBiRP8mzpYmwltMOzrktekVTA49XDRPjVmwgvQivWXcLK9Xgnn0M-CFCTQ00jX9C2Bi65WVXu2WvC7W0ezqRGx8xZfDOoXAbwib5yAJJV8PXbW_XDWDZq2KGPW2/s320/HappyNewYearAll.gif';
run;

Execute the above code and lo-behold!! You get an animated gif in your mail body as shown below:

Wish You a Merry Chirstmas!!!
And a Happy New Year!!!



Wish you all a Merry Christmas and a Prosperous New year!!!

Friday, December 10, 2010

Accessing Unix server in windows explorer

There has always been a debate between using a GUI-based, windows-freindly FTP client like WinSCP and a conventional telnet client like PuTTY. One party says that its Easy to use and doesn't need any unix knowledge to perform any operations; and the other says that one needs to have such roboust telnet clients to "keep in touch" with the commands/syntax and accept the fact that not everything in the world is "Winowized".

I did a google fight between these two and here is the winner :
http://www.googlefight.com/index.php?lang=en_GB&word1=Winscp&word2=putty

Anyway, before i digress too much, let me show you a intersting way to access your UNIX servers from windows without downloading any FTP client or a telnet client:
  • Open the Internet Explorer and type the following in the address bar and hit enter:
  • ftp://<user-name>:<password>@<server-name>
  • Now you would be able to see your unix home directory in your windows explorer if you are using IE 6. If you are using a IE 8, then click on Page and click on Open FTP Site in Windows Explorer. You may be prompted for a user id and password again.
  • Now save this link in you favourites and next time you want to login, you could just open a windows explorer and login using your credentials.

Monday, December 6, 2010

Resolve vs Symget

Symget function enjoys lot more amount of pulicity and usage as compared to the resolve function, though the later one actually is (at least according to me..) more efficient, powerful and more flexible! (Guess am becoming more sentimental these days..)

Having this in mind, i tried searching about some articles on resovle function in google but in vain. There are lot more number of articles and examples of symget usage and call execute functions as compared to the resolve functions which accomplishes both these functionality.

Resolve function resolves the value of the text expression during the data step execution. It can reslove the value of a macro variable (like symget) and also expand the macro invokation (somewhat similar to call execute, just that it expands the macro and doesn't execute it...)

I've illustrated below, a few simple examples of various uses of Resolve funtion.

Illustration 1: Macro variable resolution in a datastep (similar to symget)

data t;
dt = symget(sysdate9.);
dt1 = resolve('&sysdate9.');
run;

Both the variables in the above datastep returns a character variale of length 200 each having the value of the current date in date9. format.

Illustration 2: Mutiple macro variable resolution in a datastep (extention from symget)

data t;
dt = symget('sysdate9')||' '||symget('systime');
dt1 = resolve('&sysdate9. &systime.');
run;

We can also use resolve function to resolve multiple macro variables (which is unavailable in symget).

Illustration 3: Expansion of a Macro using resolve

%macro min;
select min(age)
from sashelp.class
%mend min;


%macro m(i);
proc sql;
create table tab12 as
select *
from sashelp.class
where age=&i;
quit;
%mend m;

data _null_;
call execute(resolve('%m(%min)'));
run;

In the above example, I use resolve function along with the call execute function which would expand the macro invokation twice (though a single resolve function is being used). Thus, the above data step does a call execute once and resolves the %m which inturn takes the arguement as %min which in turns expands. So the result code would be like this, which is shown in the log:

NOTE: CALL EXECUTE generated line.

1 + proc sql;
1 + create table tab12 as select * from sashelp.class where age=select min(age) from sashelp.class;
1 + quit;

NOTE: Table WORK.TAB12 created, with 2 rows and 5 columns.

Illustration 4: Conditional execution and execution in a data step loop

%macro sql(i,minage,maxage);

%if &i=&minage %then %do;
   Proc Sql Noprint;
   Create table tab as
   select *
   from sashelp.class
   where age = &i
%end;

%else %if &i=&maxage %then %do;
   UNION ALL
   select *
   from sashelp.class
   where age = &i;
   Quit;
%end;


%else %do;
   UNION ALL
   select *
   from sashelp.class
   where age = &i
%end;
%mend sql;

proc sql noprint;
select min(age), max(age) into : minage, : maxage
from sashelp.class;
quit;

data _null_;
do i=11 to 16;
  call execute(resolve('%sql('||i||',&minage,&maxage)'));
end;
run;

In the above example, I'm trying to append multiple datasets which are created out of sashelp.class (for each age values). Here, I'm trying to execute the %sql macro in a datastep loop, and passing both the macro variable and the data step variable as the macro parameters.

This example also shows how to conditionally execute the macro variable based on the parameters passed.

I've pasted below the log message for the above code. Also note that the iteration number is printed at the begining of the every iteration's resolution.

NOTE: CALL EXECUTE generated line.



1 + Proc Sql Noprint;
1 + Create table tab as select * from sashelp.class where age = 11
2 + UNION ALL select * from sashelp.class where age = 12
3 + UNION ALL select * from sashelp.class where age = 13
4 + UNION ALL select * from sashelp.class where age = 14
5 + UNION ALL select * from sashelp.class where age = 15
6 + UNION ALL select * from sashelp.class where age = 16;
6 + Quit;

NOTE: Table WORK.TAB created, with 19 rows and 5 columns.

Thursday, December 2, 2010

Blogger's paradise!

Recently i was invited to join a website named http://www.sas-x.com/ by  Tal Galili

I suggest everyone to subscribe to this feed. It has the aggregation of many big names in SAS blogging like  Chris Hemedinger, Mark Stevens, Jared Prins, Rick Wicklin, and many more!!

Its a privilege that my blog was added to this website...

All the best Tal!

Tuesday, November 30, 2010

Indexing in SAS.. In a baby's language

A question at the KBC (Indianized version of Who wants to be a Millionire)

If your answer happens to be anything other than C then this might not be a relevant post for you :-)

There have been innumerable number of posts on indexing in SAS. One such brilliant post is found in the below link..

http://blogs.sas.com/sastraining/index.php?/archives/55-To-INDEX-or-not-to-INDEX....html

To me, the working on a simple index is understood this way...

Note: I've considered a B-Tree index. I'm sure SAS uses other better ways to maintain the index table.

Lets consider an example where we have a dataset with 2 variables ID and Age, and having 100 observations with Id values ranging from 1 to 100.


   Now assume that i would want to execute a query as given below:
     
        Proc Sql;
           Select Id, Age
           From Tab
           Where ID = 77;
       Quit;

Now we will understand what happens to the query in two scenarios: without indexing and with indexing

Case 1 - Without indexing:

Nothing unusual happens :-) Query runs to completion! Just that the SAS Complier starts searching the number 77 sequentially from the beginning and would need to make 77 passes to make the right hit!




Case 2 - With Indexing:

If the Table is indexed, (on ID in this example) then the complier first compares if the key variable (77) is less than 50 or greater than 50. Then in compares if the key variable is greater than 75 or less than 75, and so on.. Until a match is found.


 
Thus the number of iterations here is reduced drastically in comparison to the non indexed table.
 
Note: The example considered above has just 100 observations. This was just for the ease of explaination. In reality, indexing for 100 observations would not change the performance much. However, indexing are found to be pretty efficient when the dataset size is huge.

Wednesday, November 24, 2010

Booooom!!! proc explode!!!

I came across an interesting procedure today.. Its called as proc explode!

This procedure enables the user to blow up the text in nice formatting and display it on the output screen (I think only in listing).

This reminds me of the 'banner' command in the ol' UNIX boxes.

You can try the explode procedure yourself by copy pasting the below code..


proc explode;
parmcards;
HELLO WORLD

;

And the output is as shown below:



Just a word of caution! Please be mindful about the space before HELLO WORLD in the proc explode step. It throws up an error if we forget that space because SAS expects a numeric or some specific characters in that place (some options for changing the formats of the display).

Also if you are using versions <= SAS 9.1, then you may have to execute this filename statement before the proc explode (Some bug i found!!! )
FILENAME FT15F001 '~/file1.txt';

More information about the proc explode can be got at:

http://www.sfu.ca/sasdoc/sashtml/proc/z0146882.htm

Password encryption

Many a times we come across a situation where we may need to encrypt the password which we use in the SAS programs (Example: Using a password to access a database like db2). This can be acheived by the pwencode procedure. See the example below:

filename fileref "C:\MyFolder\Pwd.txt";
proc pwencode in="My Passwd" out=fileref;
run;

The contents of the Pwd.tx is as follows:
{sas001}TXkgUGFzc3dk

Here the {sas001} denotes the method of encryption. More information on the encryption methods available/used in SAS can be found at:
http://support.sas.com/documentation/cdl/en/secref/62092/HTML/default/viewer.htm#a002595992.htm

Now the encoded password can be used everywhere by reading the contents of the file Pwd.txt.

Tuesday, November 23, 2010

Error Codes for libname

Whenever we assign a libname (especially a libname to a database), we would want to be sure that the library path should be valid/existing. When it comes to assigning a libname to a database, example oracle, we may also want to confirm if the user-id and the password are valid.

Below is the syntax for doing a error check immediately after assigning a libname and before proceeding to access the lib reference:


libname dbase oracle user="USER_ID" pass="PASSWORD" path='@PATH' schema=MYSCHEMA;

%macro code_area;
filename sendmail email to=("Pramod.R@xyz.com");
%if &syslibrc = 0 %then %do;
/* RUN THE ACTUAL CODE HERE*/
data _null_;
file sendmail subject="Success";
put / "The code ran into completion.";
run;
%end;
%else %do;
/* THROW THE ERROR MAIL */
data _null_;
file sendmail subject="Failed";
put / "The code ran into ran into problems due to Oracle connection problems.";
run;
%end;
%mend code_area;

%code_area;



Similarly we can also do a check for the filename by using the automatic macro variable - %sysfilrc, which returns a 0 value for successful filename statement and a non zero value if the filename statement failed.

.netrc in UNIX

I came across this interesting feature when i was trying to FTP a file from a FTP server to my Unix box. I used this convetional method to FTP a file earlier:

ftp -n $SERVER
quote user $LOGIN
quote pass $PASSWORD
cd ..
ls BKP files.txt




The problem with this method is that I would need to store my user id and password in the variable LOGIN and PASSWORD and read it everytime. This can be done by saving these variables in another read only file and then reading them everytime we FTP a file. Also we may need to keep updating our passwords as and when we change it.

.netrc file helps us overcome all these shortcomings. All you need to do is create a file named .netrc in your home directory and paste the following text in it:

machine login password


Then give the following permissions: -rw-------

This would help us FTP the files without having us to provide any login credentials anytime.

Wednesday, July 21, 2010

Script to remove the subversion folder from project directory

Many a times we would want to remove the subversion folders which are present in the project directory for various reasons. (Eg: Copy the structure to another drive, zip it and mail it, etc..). The subversion folders are present in every directory (Eg: .svn, .cvs, etc...).

This script, when executed in windows command mode, removes all the .cvs from the directory structure.

for /d /r . %d in (.cvs) do @if exist "%d" rd /s/q "%d"