Hello folks,
I am a very beginner at SAS coding. I want to automate part of a manual task my team has to execute weekly and was suggested to try my hand on SAS. The language seems easy to use and I was able to create a working code. The problem is that we have 200+ systems to run the task and I am having a very hard time to "universalize" the code so we can use only one source for all systems.
The idea is to run the following JCL:
//SASREPRT EXEC SAS . . . //SYSIN DD DISP=SHR,DSN=MYHLQ.RT&&AVP(SASCODE)
The 'RT&&' is a placeholder for the identification the user will have to manually enter each time this job is submitted.
This is the part of the SASCODE that reads from the LIST and, after some parsing, it will confirm the jobnames and separate them into 3 datasets:
/*-------------------------------------------------------------------------------------------------------------------------- Purpose: This DATA step splits the merged job_summary dataset into three separate datasets based on the jobname prefix. Execution Details: - Each record from job_summary is evaluated using the substr() function. - Jobs with jobnames starting with: - 'RT&&0' are categorized as RIP jobs. The output is sent to dataset rip - 'RT&&G' are categorized as SysGen jobs. The output is sent to dataset sysgen - 'RT&&MN' are categorized as Maintenance jobs. The output is sent to dataset maint - Each matching record is written to its respective dataset using output. Assumptions: - Jobname prefixes are consistent and meaningful for classification. - Only one category applies per job (no overlaps). --------------------------------------------------------------------------------------------------------------------------*/ data rip sysgen maint; set job_summary; if substr(jobname, 1, 5) = 'RT&&0' then output rip; else if substr(jobname, 1, 5) = 'RT&&G' then output sysgen; else if substr(jobname, 1, 6) = 'RT&&MN' then output maint; run;
Is there anyway to pass a PARM on the JCL that would dynamically change the RT&& inside SASCODE for that specific run?
Example: User edits the SASREPRT and change RT&& to ABCD. When the job is submitted, the RT&& is dynamically changed in the SASCODE as well. For this to be universal and reusable, SASCODE would have to remain with RT&& after the job is executed.
Thanks in advance,
Fábio "Morfasio" Silva
Hello Tom, thank you for the reply. And sorry for the delay in getting back to you.
I've tried your suggestion but it didn't work, the value was not replaced.
I was checking with my colleagues from the performance team (they run reports for virtually everything here) and was told about a library full with all sort of SAS source codes. I've found a code which have the variable defined and the calling is defined in a way I didn't see previously in a JCL.
This is the update to my SAS:
data _null_; call symput('IMSID',' '); /* Initialize IMSID macro variable */ data _null_; infile setup missover; /* Read from SETUP DD */ input @1 check $1. @; if check='*' then do; input; return; end; /* Skip comment lines */ input @1 text $14.; if text=: 'IMSID=' then do; text=substr(text,7,4); /* Extract IMSID value */ call symput('IMSID',text); /* Set macro variable */ end; run;
And in the JCL I had to add a SETUP DD card right before the SYSIN:
//SETUP DD * *IMSID= IDENTIFIES THE IMS SYSTEM ID IMSID=ABCD
It worked and created the report I wanted. As today is Friday and we are too close to the "happy hour", I'll resume the tests next week.
Once again, thanks for the suggestion. Have a nice weekend.
Regards,
Fábio "Morfasio" Silva
Haven't used JCL in over 20 years, but SAS has had major enhancements in that time so perhaps you could use SAS code to do what you want?
For example can you use the FILENAME= option on an INFILE statement to figure out want the DSN= value was in the JCL DD statement?
Hello Tom, thank you for the reply. And sorry for the delay in getting back to you.
I've tried your suggestion but it didn't work, the value was not replaced.
I was checking with my colleagues from the performance team (they run reports for virtually everything here) and was told about a library full with all sort of SAS source codes. I've found a code which have the variable defined and the calling is defined in a way I didn't see previously in a JCL.
This is the update to my SAS:
data _null_; call symput('IMSID',' '); /* Initialize IMSID macro variable */ data _null_; infile setup missover; /* Read from SETUP DD */ input @1 check $1. @; if check='*' then do; input; return; end; /* Skip comment lines */ input @1 text $14.; if text=: 'IMSID=' then do; text=substr(text,7,4); /* Extract IMSID value */ call symput('IMSID',text); /* Set macro variable */ end; run;
And in the JCL I had to add a SETUP DD card right before the SYSIN:
//SETUP DD * *IMSID= IDENTIFIES THE IMS SYSTEM ID IMSID=ABCD
It worked and created the report I wanted. As today is Friday and we are too close to the "happy hour", I'll resume the tests next week.
Once again, thanks for the suggestion. Have a nice weekend.
Regards,
Fábio "Morfasio" Silva
Just some comments on the example SAS code you posted.
If you want to set a macro variable you don't need to run a data step;
%let imsid=;
You almost never want to use the extremely ancient MISSOVER option or the merely ancient CALL SYMPUT() method. Instead use the modern TRUNCVOER option and the CALL SYMPUTX() method.
The only reason to use MISSOVER is if you want INPUT to ignore text at the end of line that is too short for the informat width being used.
The only reason to use CALL SYMPUT() is if you want the generated macro variable to have leading and/or trailing spaces.
The reasons that example would work using those ancient options/methods is
1) Because you are reading from a card deck the data lines will contain 80 characters even when the number of non blank characters is less than the 14 bytes you are reading.
2) Your usage of the IMSID macro variable most not mind the extra 10 spaces that you stored into the value by using CALL SYMPUT() with a character variable defined to store 14 bytes.
Of course you could also use the ancient NAMED INPUT style of reading data.
/* Initialize IMSID macro variable */
%let imsid= ;
/* Read IMSID from SETUP */
data _null_;
infile setup ;
input @'IMSID=' imsid :$4.;
call symputx('imsid',imsid);
run;
I think this https://www.lexjansen.com/nesug/nesug07/po/po13.pdf may get you started.
Bascially the idea is using a SAS Macro variable, the bits in SAS that look like &YR1 and &YR2 and then supply the values on a JCL RUN statement.
Note that you will want to look up the rules involved in valid SAS Macro variables (reference starts with & followed by letters, digits or _ character ) and that they will only resolve inside double quotes if the value needs to have quotes when used.
So instead of RT&&0 you might use a macro variable &RT that would be defined to have the value ABCD. To suffix the value with a 0 you would use &RT.0 in the SAS code as the . tells SAS where the end of the macro variable name is so doesn't go looking for a longer variable name.
So this code:
if substr(jobname, 1, 5) = 'RT&&0' then output rip; else if substr(jobname, 1, 5) = 'RT&&G' then output sysgen; else if substr(jobname, 1, 6) = 'RT&&MN' then output maint; run;
Might be come
if substr(jobname, 1, 5) = "&RT.0" then output rip; else if substr(jobname, 1, 5) = "&RT.G" then output sysgen; else if substr(jobname, 1, 6) = "&RT.MN" then output maint; run;
And the call might look something like
//RUN1 EXEC YOURPROG,RT=ABCD
In my case, I haven't written a JCL SAS program since 1991 so made a guess for a google search using SAS JCL PARMBUFF (as parmbuff is one of the things I vaguely remembered using related to this)
Hi ballardw, thanks for the reply.
I tried this solution before creating the post here. I had 2 issues with that:
- //SASREPRT EXEC SAS ---> The SAS here is not a PGM, it's a homegrown way to access the SAS codes, like a proc. Anything I put after the SAS has to be SAS pre-defined command or structure.
- &RT.0 ---> Although the job completed fine (RC=00), the result was not the expected and the list in the report came up empty.
As I posted in my last, I've found a working solution after talking to the team that does the metrics with JCL and SAS. My issue now seems to be fixed... now I'll run some more tests in the sandbox and see if it suits the need to be universal/reusable code.
This was my very first try with SAS so I must certainly got the code wrong at some point or didn't pass the correct instructions. I'll definitely keep reading the manuals and exercises, this seems to be a nice way to code in a tight spot.
Thank you for the suggestion and have a great week.
Fábio "Morfasio" Silva
It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.
SAS' Charu Shankar shares her PROC SQL expertise by showing you how to master the WHERE clause using real winter weather data.
Find more tutorials on the SAS Users YouTube channel.