I am using below code to seperate ady variable , but it gives me error ' Expected close parenthesis after macro function invocation not found.' i have tried using compress and tranwrd function. but it says the same thing.
options mlogic mprint symbolgen;
%MACRO VLIST(in= , col = ,typ= );
data vlist;
length col0001 $1000;
set &in.;
%if &typ. = DD %then %let n1 = %sysfunc(countw("&col.",'('));
%put &n1.;
array ddjoin(*) $ var1 - var&n1.;
%do i = 1 %to &n1.;
%if &i eq 1 %then ddjoin(&i.) = %sysfunc(scan(&col.,&i.,'('));
%if &i ne 1 %then ddjoin(&i.) = %sysfunc(scan( %sysfunc(scan(&col.,&i.,'(')), %eval(&i.-1),')'));
%end;
if cmiss(var1,var2) = 0 then col0001 = strip(var1) || '(' || strip(var2) || ')';
run;
%MEND VLIST;
%vlist(in=b, col = adt(ady), typ = DD );
Check this line - you miss ')' at end of it
%if &typ. = DD %then %let n1 = %sysfunc(countw("&col.",'('));
This line is fine. it has 2 open brackets and 2 close brackets.
%if &i ne 1 %then ddjoin(&i.) = %sysfunc(scan( %sysfunc(scan(&col.,&i.,'(')), %eval(&i.-1),')'));
This is the line,that is throwing the error.
it has same number of open and close brackets, i have also tried replacing brackets in input with some other symbol. but issue remains same.
Why are you using brackets as separators in a string? Go back to the place where the string is created, and use a separator that makes sense.
Or replace the dumb brackets with something else in a data step before you invoke the macro.
i have also tried replacing brackets in input with some other symbol. but issue remains same.
The best separator for variable names is the blank, as blanks are not valid in SAS names anyway.
So see this example for how it works:
%let varstr=adt adg;
%macro teststring(col=);
%do i = 1 %to %sysfunc(countw(&col));
%let var = %scan(&col,&i);
%put var=&var;
%end;
%mend;
%teststring(col=&varstr);
Seems to be usage of macro statements where normal data-step-statements are required. If you need the scan-function in the macro-world, use %scan and don't use quotes when passing strings to macros.
@sas_user wrote:
I am using below code to seperate ady variable , but it gives me error ' Expected close parenthesis after macro function invocation not found.' i have tried using compress and tranwrd function. but it says the same thing.
options mlogic mprint symbolgen;
%MACRO VLIST(in= , col = ,typ= );
data vlist;
length col0001 $1000;
set &in.;
%if &typ. = DD %then %let n1 = %sysfunc(countw("&col.",'('));
%put &n1.;
array ddjoin(*) $ var1 - var&n1.;
%do i = 1 %to &n1.;
%if &i eq 1 %then ddjoin(&i.) = %sysfunc(scan(&col.,&i.,'('));%if &i ne 1 %then ddjoin(&i.) = %sysfunc(scan( %sysfunc(scan(&col.,&i.,'(')), %eval(&i.-1),')'));
%end;
if cmiss(var1,var2) = 0 then col0001 = strip(var1) || '(' || strip(var2) || ')';
run;
%MEND VLIST;
%vlist(in=b, col = adt(ady), typ = DD );
I tried using like this:
%if &i eq 1 %then ddjoin(&i.) = %scan(&col.,&i.,'(');
%if &i ne 1 %then ddjoin(&i.) = %scan(%scan(&col.,&i.,'('), 1, ')');
This is the log:
NOTE: Line generated by the invoked macro "VLIST".
7 ddjoin(&i.) = %scan(%scan(&col.,&i.,'('), 1, ')')
------
22
SYMBOLGEN: Macro variable COL resolves to aphase(aperstdy)
SYMBOLGEN: Macro variable I resolves to 2
ERROR: Macro function %SCAN has too few arguments.
NOTE: Line generated by the invoked macro "VLIST".
7 ddjoin(&i.) = %scan(%scan(&col.,&i.,'('), 1, ')')
-
390
ERROR 22-322: Syntax error, expecting one of the following: !, !!, &, (, *, **, +, -, /, ;, <, <=, <>, =, >, ><, >=, AND, EQ, GE, GT, LE,
LT, MAX, MIN, NE, NG, NL, OR, [, ^=, {, |, ||, ~=.
ERROR 390-185: Expecting an relational or arithmetic operator.
MLOGIC(VLIST): %DO loop index variable I is now 3; loop will not iterate again.
NOTE: Line generated by the invoked macro "VLIST".
7 ddjoin(&i.) = %scan(%scan(&col.,&i.,'('), 1, ')')
-
200
ERROR 200-322: The symbol is not recognized and will be ignored.
MPRINT(VLIST): ddjoin(1) = aphase ddjoin(2 ) = , 1, ')') ;
MPRINT(VLIST): run;
NOTE: Character values have been converted to numeric values at the places given by: (Line):(Column).
1:3 7:2 7:47
NOTE: Numeric values have been converted to character values at the places given by: (Line):(Column).
5:2
NOTE: The SAS System stopped processing this step because of errors.
What is it your actually trying to do here? It looks to me like you have created a very complicated way of doing something very simple. Provide some test data and show what you want out, and will give a simple datastep example of how to do it.
I am trying to create a macro here, that will create a listing dataset. in my data i have a column to present date and day in date(day) format.
I want my user to just give variable names in the format he wants in the output. so that he do not have to pass so many parameters to tell macro what kind of join it wants, but the macro finds it out itself.
so if my user is passing col = adt(ady), i want my macro to separate both variables and join them in adt(ady) format.
I hope it helps.
I agree with @RW9 that you are making this an extremely difficult problem and there has to be an easy way. Look at these lines from your code:
%if &i eq 1 %then ddjoin(&i.) = %sysfunc(scan(&col.,&i.,'('));
%if &i ne 1 %then ddjoin(&i.) = %sysfunc(scan( %sysfunc(scan(&col.,&i.,'(')), %eval(&i.-1),')'));
Without any errors, these would generate:
ddjoin(1) = adt
ddjoin(2) = ady
Surely these are not the statements you want to appear in your DATA step. At a minimum you would want a semicolon ending those statements, and you might want quotes around the values being assigned.
Give an example of what the desired output would look like. There is almost certainly an easy way to get there.
I am trying to create a macro here, that will create a listing dataset. in my data i have a column to present date and day in date(day) format.
I want my user to just give variable names in the format he wants in the output. so that he do not have to pass so many parameters to tell macro what kind of join it wants, but the macro finds it out itself.
so if my user is passing col = adt(ady), i want my macro to separate both variables and join them in adt(ady) format.
ddjoin(1) = adt
ddjoin(2) = ady
this is exactly what i want. but it is throwing errors for ddjoin(2).
so once both are seperated, it can be joined as:
if cmiss(var1,var2) = 0 then col0001 = strip(var1) || '(' || strip(var2) || ')';
I hope it helps.
Nope you lost me. You keep talking about a join, are you merging data? Or is it to create a concatenated variable from two variables? If its this, I don't how this macro will actually benefit you. A simple cats() will take strings, or convert numbers implicitly, again making checking types irrelevant. It is one of the big failings with macro language as used in that it adds extra layers of complexity, reduces functionality, and is mainly undocumented appropriately. You creating code to do something very specific, which doesn't actually need to be done , you have posted the code you should yourself, with a minor change:
if cmiss(var1,var2)=0 then col0001=cats(var1,'(',var2,')');
Generating loads of macro around that will not add anything to that code, and will cost you many hours in build, test, documentation, and support to implement.
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!
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.
Select SAS Training centers are offering in-person courses. View upcoming courses for: