HI
I have two different datasets where I want to identify the matching values .
For example in the below code I have used both similar datasets (in real both are different). Here I would like to get local as the macro variable but uanble to graple the value with in one call. could any one please help me how to resolve macro variable by calling a macro from datastep.
%global temp;
%let temp = %str(std='yes');
%macro test(name);
data _null_;
set sashelp.class;
if name=&name then do;
call symput("temp",%str(local='yes'));
stop;
end;
%mend;
data xyz;
set sashelp.class;
call execute('%test('||name||')');
&temp;
run;
One way to code such a test is to take advantage of the CANCEL option on the RUN statement. So first create an empty macro variable and then while reading the first file conditionally set the macro variable to contain the keyword CANCEL. Then reference the macro variable in the second data step that reads the second data file.
%let run_cancel=;
data _null_;
infile 'file1' ;
input;
if _infile_=: 'RSS' then do;
call symputx('run_cancel','cancel');
stop;
end;
run;
data want ;
infile 'file2' ;
input ....... ;
run &run_cancel ;
Check SYMGET() or RESOLVE().
did not resolve my issue, if possible could you please try the sample code.
You should use PROC COMPARE to compare datasets.
As to your posted code if you just look at the SAS log it will be obvious what is happening and why that method is not very useful.
First the data set XYZ is created and then there are 19 more data steps that are generated by your CALL EXECUTE() statement that are run. This is becuase the CALL EXECUTE function just pushes code onto the stack to be executed after the current data step finishes.
Also notice that the data set XYZ will have the variable STD set to 'yes' since when that data step was prepared for execution the value of the TEMP macro variable was std='yes'. So your data step is resolves to:
data xyz;
set sashelp.class;
call execute('%test('||name||')');
std='yes';
run
Now the CALL EXECUTE will run the %TEST() macro and push any code that it generates onto the stack so that it can execute after the XYZ dataset is created. So for example it will push code like this data step.
data _null_;
set sashelp.class;
if name=Alfred then do;
call symput("temp",local='yes');
stop;
end;
In addition to problem of the code running after the XYZ step is finished there are other problems with this code. First there is no variable named ALFRED in the SASHELP.CLASS dataset. I assume that you intended to generate "Alfred" instead so that it would be interpreted as a string literal instead of a variable name. So the IF statement is never true so the CALL SYMPUT() function never runs. But note that it also has trouble since you are referencing the variable LOCAL which does not exist. Since this will never be equal to 'yes' the CALL SYMPUT statement would have always set the macro variable TEMP to the number zero converted to a text string using the BEST12. format, so eleven spaces followed by the digit 0. Also notice that your generated code does not contain a 'RUN;' statement to terminate the data step.
Could you please tell me how the call execute will work in the code below? I know that it will call the 'test' macro , but I don't understand the other thing which is enclosed in single quotes '||name||'
data xyz;
set sashelp.class;
call execute('%test('||name||')');
std='yes';
run
Thanks in advance!
|| is the concatenation operator. So '%test(' || name || ')' says to sandwich the value of the variable NAME between the two string literals. So it if the value of NAME is 'Alfred ' then the string passed to CALL EXECUTE will be '%test(Alfred )'. Now that SAS has introduced the CAT... series of functions I find that I use them more often than the simple concatenation operator. So you could use CATS('%test(',name,')') instead. Note that the CATS() function will also trim the trailing spaces from the value of the NAME variable.
If you use this syntax then the %TEST() macro call will execute immediately and any SAS code it generates will be pushed onto the stack to run after the current data step finishes. But any macro code that the macro has will execute immediately. That is why normally it is helpful to add %NRSTR() macro function around the macro call to prevent the macro from executing immediately. Instead the macro all will be placed on the stack and then the macro will execute after the current data step finishes.
data xyz;
set sashelp.class;
call execute('%nrstr(%test)('||name||')');
std='yes';
run
Hi Babloo,
the enclosed one is a parameter to the macro.
Example: If you want to pass some value to the macro then you can pass the variable value in it for each observation.
if you have a dataset with name as the variable name (4 names) then all four times it will pass and call the calling macro.
data test;
input name $;
datalines;
kumar
akash
vinay
babloo
;
%macro printmacro(name);
%put These are very good guys : &name.;
%mend;
data _null_;
set test;
call execute('%test('||name||');
run;
Here the print macro will be called 4 times (as many observations as test dataset has) and prints the output to the log.
Hope answered the question.
Here's one way to find if a specific value occurs in a data set for a variable:
proc sql noprint;
select (count(name)>0) into : temp
from sashelp.class
where name="&name";
quit;
The macro variable temp will have a value of 1 (found) or 0 (not found). Note that just as your attempted code would not match ALFRED to Alfred, case or leading spaces will not match. You might want to consider addressing those points for your application.
If you just want to match records on value of a variable then use a MERGE statement.
data want ;
merge one two ;
by id;
run;
Thank you for the replies. well I have a confusion of how call execute works. My issue is to restrict the reading of text file based on condtion (so I created a macro and a sample example).
For example:
I have to read a text file
filename in "c:/temp.txt";
data test;
infile in truncover;
input x $500.;
if x > 'some value then only i need to create dataset or else discard reading the file';
/*Here i might need previous observations if this condition is true */
/*Value of x may come in nth row */
run;
data test;
infile in truncover;
Is this the same problem or a new one?
Not much way to do this without reading the file twice. Once to determine if the problem value exists and then again to generate the dataset. Or you might actually be able to use CALL EXECUTE for this problem by creating the dataset and then conditionally deleting it (or perhaps renaming it).
data WANT;
infile "c:\temp.txt" truncover;
input x $500.;
if x > 'some value then only i need to create dataset or else discard reading the file' then do;
call execute('proc delete data=WANT;run;');
stop;
end;
run;
Thanks tom,
Its the same issue which I posted . I had some logic running and was not working in between to solve reading text file.
want to add few more points
1. I thought to create a flag (retain varialbe) and continue reading the text file.
2. text file reading has many conditions and want to improve performance.
if there is any other solution to read a text file (optimized way, as it got 100's of condtions in it)
In general if the question is how to read a complicated text file into a nice structured data set then conditional programming is the answer and not generated code. Figure out a data structure that can store the information and then write a data step (or series of steps) to create that structure from the source file. For example look at this posting on Stack Overflow. https://stackoverflow.com/questions/34533980/reading-hierarchicalish-data-into-sas/34547963#34547963
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.