So I am creating a macro to score a questionnaire. So the first part of the macro is calculating a raw score... and the second part is converting the raw score to a standardize score, where the standardize score would come from an existing table. I want this macro to be a stand alone program (called by my autoexec) so it can be moved from project to project.
I understand that I can't use Datalines/Cards within a macro. I am trying to figure out is there a workaround for this?
This is basically this is what I want, but the cards statement doesn't work in macros. I only thing I can think of is use the If/Then statement (so if rawscrore=1 then standarscore=14.5.. etc.). But I am wondering if there is an easier way to do this? Since it would be 200 lines (raw score can range from 1-200) if I were to use the if/then statement;
Sample code:
%Macro score; *Some code to calculate the raw score variable; Data have; set fromscoringcodeabove (Keep=ID Rawscore); run; Data Standardscoretable; input Rawscore standardscore; cards; 1 14.5 2 17.9 3 20.5 4 24.4 ; data want; merge have (in=a) Standardscoretable; if a; by Rawscore; run;
%mend score;
If your'e on a platform w/PIPE support:
%macro testio;
Filename in pipe 'echo 1 14.5 2 17.9 3 20.5 4 24.4 ';
Data Standardscoretable; infile in; input Rawscore standardscore@@;
%mend;
%testio;
run;
If you go multi-line with the data, make sure each line has a trailing space!
Use a format (defined with proc format) and the input function to convert raw to standardized scores.
Actually I didn't thikn of that. That might be easier then if/then statements
If you just want to make such a simple dataset then there is no need for CARDS/DATALINES.
data standardscoretable;
do standardscore=14.5,17.9,20.5,24.4;
rawscore+1;
output;
end;
run;
the dataset is just an example. there are over 200 records 🙂
200 records is nothing. Copy and paste them into your program file.
If you don't want to put in the commas you can use a simple program to generate the list from an existing dataset with the commas between the values and just copy from that little file into your source code.
filename list temp;
data _null_;
set mydataset ;
file list;
retain sep '=';
put sep standardscore;
sep = ',' ;
run;
Or use a macro variable in your autocall macro. Then you can copy and paste from your source file and not worry about having to insert commas to make it look like code.
%let standardscores=14.5 17.9 20.5 24.4;
data standardscoretable;
do rawscore=1 to countw(symget('standardscores'),' ');
standardscore=input(scan(symget('standardscores'),rawscore,' '),32.);
output;
end;
run;
There are several ways. One quick way is given. An Array is used to lookup - giving the Rawscore and to get the corresponding standardscore. This array can hold a maximum of 200 rawscores. In case it is more, you may replace it by the maximum value. Even a million can be held in the array if you want. I have used HAVE to mimic your rawscore data set. Here goes your Macro:
data have;
input ID Rawscore;
datalines;
1 1
2 1
3 2
4 2
5 3
6 4
7 3
;
run;
Data Standardscoretable;
input Rawscore standardscore;
cards;
1 14.5
2 17.9
3 20.5
4 24.4
;
run;
%macro score;
data want;
format ID Rawscore newScore;
if _N_ = 1 then do;
array k[200] _temporary_;
do until(eof);
set Standardscoretable end = eof;
k[Rawscore] = standardscore;
end;
end;
set have;
newScore = k[Rawscore];
drop standardscore;
run;
%mend;
%score;
proc print data = want;
run;
Enjoy the Macro.
Here's one of those should-I-be-proud-or-ashamed-of-this kludges. 🙂
%macro testio; %let input= 1 14.5 2 17.9 3 20.5 4 24.4 ; filename io "%sysfunc(pathname(work))/workio.txt" lrecl=32767; data _null_; file io; put "&input"; Data Standardscoretable; infile io; input Rawscore standardscore@@; %mend; %testio; run;
I think many of us have at times become obsessed with trying to get the equivalent of CARDS (SAS), SYSIN (MAINFRAME), or HERE DOCUMENTS (UNIX) to play nice with SAS macros.
Here's my own Coders' Coder stab at a more general solution from 10+ years ago:
A Better SYSIN Than SYSIN: Instream Files on Any Platform
I had hoped the new PROC STREAM might work inside macros, but I couldn't figure out a way to get it to work (please correct me if I messed up and there's a way!).
Stil, even if it doesn't work inside a macro, a quick glance at some papers Google turned up by Don Henderson and Rick Langston suggests there are some insanely great (or insanely insane!) things you can do with PROC STREAM, so I'll have to check it out.
If your'e on a platform w/PIPE support:
%macro testio;
Filename in pipe 'echo 1 14.5 2 17.9 3 20.5 4 24.4 ';
Data Standardscoretable; infile in; input Rawscore standardscore@@;
%mend;
%testio;
run;
If you go multi-line with the data, make sure each line has a trailing space!
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn the difference between classical and Bayesian statistical approaches and see a few PROC examples to perform Bayesian analysis in this video.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.