i am facing a problem as I tryiing to make a string by using SAS Macro and SAS functions but am not able to deal with parentheses as a string. Don't know what to do.
Can someone please help me with this.
My Code :
%MACRO MA_STRING(D,N) ;
%LET MA_STRING = %NRSTR(sum%() ;
%PUT &MA_String ;
%DO I = 1 %TO &N ;
%LET MA_STRING = %SYSFUNC(CAT(&MA_String ,%STR(,) , LAG , &I , %Str(%() , &D , %Str(%)) ));
%PUT &MA_String ;
%END ;
%MEND ;
%MA_STRING(P,3) ;
This is the error received.
sum(
ERROR: Required operator not found in expression: )
sum(,LAG1.P)
ERROR: Required operator not found in expression: sum(,LAG1.P)
ERROR: Required operator not found in expression: )
sum(,LAG1.P),LAG2.P)
ERROR: Expected close parenthesis after macro function invocation not found.
LAG , 3 , ( , P , ) ))
It really helps to describe what you are attempting to do. And provide examples of input and desired output.
And when working with macros an example of the code that worked without any macro elements.
As @ballardw please explain what you're trying to do and provide sample data.
On top of this: SAS Macro code generates SAS code. It appears you're trying to generate SAS code which contains the LAG() function. If so then the LAG() function must be used in a SAS Data step and you certainly can't call the macro outside of a SAS data step.
Notice you have additional problems besides the parenthesis. The code you are trying to create cannot run, since even if it worked you would end up with:
sum(,lag1(P), lag2(P))
The first item to sum isn't specified.
This might work or might not. I just can't test it right now:
%LET MA_STRING=sum(
%do i=1 %to &n;
lag&i(&d)
%if &i < &n %then ,;
%end;
);
But even if it does work, it would be cleaner and more flexible to get rid of the %LET piece.
%macro MA_STRING (D, N);
%local i;
sum(
%do i=1 %to &n;
lag&i(&d)
%if &i < &n %then ,;
%end;
)
%mend MA_STRING;
Then within a DATA step you could call the macro to assign a value to a DATA step variable:
MA_STRING = %MA_STRING(P,3);
Notice that you are not locked in to using MA_STRING as the name of the variable being assigned a value.
The best place to do string processing is in a DATA step. Then you can use regular string functions with no worries about quoting, etc. When you are done, you can use SYMPUTX if necessary to make a macro variable.
@Astounding This code worked successfully.
%macro MA_STRING (D, N);
%local i;
sum(
%do i=1 %to &n;
lag&i(&d)
%if &i < &n %then ,;
%end;
)
%mend MA_STRING;
Then within a DATA step you could call the macro to assign a value to a DATA step variable:
MA_STRING = %MA_STRING(P,3);
Is there a macro code to make a dataset from the string values.
eg my string is :
Bat Ball Apple
now I want something like this
Colname No.
Bat 1
Ball 2
Apple 3
What I am doing is I am creating a dataset for each word and then merging all the three datasets into one but I was wondering if there
is some other way so that I dont have to create a dataset for each word because it is taking a lot of memory.
Of course SAS can do that. But I'm tempted to say that you would probably be better off starting over again, and reconsidering your approach. It sounds like you are jumping through hoops, making an easy process complicated. If you were to post a separate question showing your original starting point, you could get some guidance on that.
You don't say whether your incoming string is contained in a macro variable or in a DATA step character variable. The answer would be slightly different, but would essentially use the same tools. The output you are showing would be a SAS data set regardless. So assuming the original string is a macro variable:
data want;
length colname $ 32;
do number = 1 to countw("&string");
colname = scan("&string", number, ' ');
output;
end;
run;
@Astounding Thanks for all your help, really appreciate it and I think I got both your codes.
In the first code where we are making a string using macro,
What we are basically doing here is, when we give a statement in a macro withour referencing it to anything else then it is taken as the output of the macro so we can use it in a datastep using %jj(i,3) and it give the value which is wriiten directly in a macro whithout any reference.
In the second code where we are making a dataset using string,
What solved my problem here is the small output command you mentioned in you code because I was facing the issue of colname being overwriiten everytime the code runs and the final output was only showing the last word of the string but now with the output statement you resolved this issue also.
And now I can't help it from being a little greedy and want to ask for a help once again.
Suppose I have a dataset in this format.
ClassA Subjects Marks
Rahul Maths 95
Raj English 75
John Accounts 97
And I want a dataset something like this.
Category Value
ClassA Rahul
ClassA Raj
ClassA John
Subjects Maths
Subjects English
Subjects Accounts
Marks 95
Marks 75
Marks 97
Now what I am doing is I am using Proc sort with nodupkey for each column and creating a dataset for each column i.e. ClasssA Subjects Marks. eg of a data set.
Category Value
ClassA Rahul
ClassA Raj
ClassA John
Then I am merging three datasets together.
Is there a short method for this task also.
Given that you know the variable names, it's straightforward. You may need to ignore some messages about numeric to character conversion.
data want (keep=category value order);
set have;
length category value $ 20;
order=1;
category='ClassA';
value = ClassA;
output;
order=2;
category='Subjects';
value = Subjects;
output;
order=3;
category = 'Marks';
value = left(marks);
output;
run;
proc sort data=want;
by order;
run;
Still, I doubt the wisdom of doing this. If the data ever gets sorted differently, you can lose the relationship between the class, the subject, and the mark.
@Astounding But your code will paste all the column values and I want only the unique values of the column.
"Then I am merging three datasets together."
The way I understand what you describe and given your sample data you would end up where you've started from after this merge.
The sample data you provide is already unique per row. It's also not really clear from your description if you're after unique rows or after unique values per variable. If it's after unique values per variables then I don't understand what you're trying to merge together as you'll loose the connection between the values (i.e. that it was Rahul who had a mark of 95 in maths).
Can you please explain a bit better and most importantly provide better sample data which demonstrates what you're after.
Then you'll have to show a more specific example ... one that actually starts with duplicates and what the end result should look like. You could easily end up with more observations for MARKS than for SUBJECTS in the final data set. It's possible that what you are doing now is just fine. It's also possible that maintaining the order (as my program did) is not important. There are just too many guesses when these cases aren't illustrated and the final result should be "something like" the illustrated result.
Heed @WarrenKuhfeld's advice.
DO NOT HANDLE DATA WITH MACRO LANGUAGE!
Use a data step and save the results with call symput/call symputx.
%MACRO MA_STRING(D,N) ;
%LET MA_STRING = %NRSTR(sum%() );
%PUT &MA_String ;
%DO I = 1 %TO &N ;
%LET MA_STRING = %SYSFUNC(CAT(&MA_String ,%STR(,) , LAG , &I , %Str(%() , &D , %Str(%)) ));
%PUT &MA_String ;
%END ;
%MEND ;
%MA_STRING(P,3) ;
I think that is the problem.
Available on demand!
Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.
What’s the difference between SAS Enterprise Guide and SAS Studio? How are they similar? Just ask SAS’ Danny Modlin.
Find more tutorials on the SAS Users YouTube channel.