Try again. This code will not work. It is a stupid code but still do not work.
data work.colnames;
input cols $;
cards;
U1
B1
;
run;
data work.test;
input rp_U1 $ rp_B1 $;
cards;
col1 col2
;
run;
%macro maketest;
proc sql;
select cols
into :col separated by " "
from colnames;
quit;
%do i=1 %to 2;
%let c = %qscan(&col,&i);
%put rp_&c;
proc sql;
create table test&i as
select
rp_&c
from work.test;
quit;
%end;
%mend;
%maketest;
I do get this error:
ERROR 22-322: Syntax error, expecting one of the following: !, !!, &, *, **, +, ',', -, '.', /, <, <=, <>, =, >, >=, ?, AND, AS,
CONTAINS, EQ, EQT, GE, GET, GT, GTT, LE, LET, LIKE, LT, LTT, NE, NET, OR, ^=, |, ||, ~=.
Which I find strange is if I try to get the columns without the rp_ this code works find. Also change
select
rp_&c
to
select
&c
The macro quoting you introduced by using %QSCAN() function instead of the %SCAN() function is probably causing trouble for the SAS parser.
In your code the macro variable C gets assigned the values of U1 and B1, respectively. But the values are macro quoted. So when the parser sees rp_&c it thinks that those are two separate tokens so it treats it like token rp_ followed by the token U1 instead of a single token of rp_U1.
You should not need to quote a string that will be part of a variable name, so you should change
%let c = %qscan(&col,&i);
to
%let c = %scan(&col,&i);
But if you do need to have the macro quoting then you can use the %unquote() function to remove it. So change
select rp_&c
to
select %unquote(rp_&c)
Related
I have the following code in a macro:
...
data HE2update (drop=sum_values n_values);
set dst_end_update;
by short_date HE;
%if HE=2 or 3 %then %do;
sum_values+value;
n_values+1;
%if HE=2 %then delete;
%else %if HE=3 %then %do;
value = round(sum_values/n_values);
HE=2;
%end;
%end;
%if HE>3 %then HE=HE-1;
%else HE;
run;
I am getting the following Error: ERROR 22-322: Syntax error, expecting one of the following: !, !!, &, *, **, +, -, /, <, <=, <>, =, >, ><, >=, AND, EQ, GE, GT, IN,
LE, LT, MAX, MIN, NE, NG, NL, NOTIN, OR, ^=, |, ||, ~=.
The error seems to be with the last if/then/else statement I don't see what I need to correct. Any help would be greatly appreciated.
The macro processor is used to generate code, not operate on data.
Your first %IF is testing whether the string HE is equal to 2 (which is false) and then OR ing the result with the number 3 (which is true) so the test is true which means these two statements are generated to include in your data step.
sum_values+value;
n_values+1;
The other two %IF tests in that %IF/%THEN/%DO/%END block are both false since the string HE does not equal either the digit 2 or the digit 3.
Then finally you test if the string HE is larger than the digit 3 which is TRUE since H is after 3 in the ASCII collating sequence. This means your program will generate the code
HE=HE-1
Notice that there is no closing semi-colon for that assignment statement. The semi-colon in the program marks the end of the %IF/%THEN statement.
So the code you generated is:
data HE2update (drop=sum_values n_values);
set dst_end_update;
by short_date HE;
sum_values+value;
n_values+1;
HE=HE-1 run;
That last assignment statement is not valid SAS syntax. Plus there is no RUN; to end the data step.
I don't think you need macro logic here at all.
data HE2update (drop=sum_values n_values);
set dst_end_update;
by short_date HE;
if HE in (2, 3) then do;
sum_values+value;
n_values+1;
if HE=2 then delete;
else if HE=3 then do;
value = round(sum_values/n_values);
HE=2;
end;
end;
if HE>3 then HE=HE-1;
run;
I create a marco array using:
proc sql;
select distinct variable into:numVarList separated by ' ' from Map_num;
I used:
%put &numVarList{1};
and it gave me all variables:var1 var2 var3{1}
how to use index to pick out macro array variable?
update 20180305
it is strange that
%put &numVarList.;
then I got:age agenc_non_ccbt_fnd_bal chmtpd_tmpnt_bal crnyr_cnter_tdnum
%put %sysnc(scan(&numVarList.,1,str( )));
I got:age agnc_non_ccb
why?and how to fix it?
You do not create an array with your select. The result is just a string: var1 var2 var3
However you can access each element with the scan-function:
%let first_ele = %scan(&numVarList.,1,%str( ));
The result is: var1
You can also loop your string like this:
%do i=1 %to %sysfunc(countw(&numVarList.,%str( )));
%put %scan(&numVarList.,&i.,%str( ));
%end;
Concatenation of values
proc sql;
select distinct variable into:numVarList separated by ' ' from Map_num;
populates a single macro variable with a value, that can be construed as a list, which is a concatenation of the distinct values in the column named "variable".
For such a list you would scan out the individual items as shown by #zuluk.
In your case when the original values are names of variables, the resolution of the concatenation can be used directly as part of a SAS statement that accepts variable name lists, such as Proc PRINT; VAR &numVarList or DATA _NULL_; ARRAY v &numVarList
Macro array
The concept macro-array is simply a set of macro variables (which can be thought of as 'symbols' when too many 'variable' ideas are colliding) with a common basename and increasing numeric suffix. Such a set of macro variables is created by using a slightly different syntax in Proc SQL.
select distinct variable
into :symbol1-:symbol9999
from Map_num
The 9999 represents a large number that you do not expect to exceed. If the data has N <= 9999 rows then only N macro variable will be created. If N > 9999 rows only 9999 macro variables will be created. Caution: Too many macro variables can fill the macro symbol table and cause errors in your SAS. For me, Macro arrays are more a programming concept than a programming construct.
For example
Proc SQL noprint;
select name into :name1-:name9999 from sashelp.class;
%let name_count = &sqlobs;
quit;
%put NOTE: &=name1;
%put NOTE: &=name2;
%put NOTE: name&name_count=%superq(name&name_count); * almost same as next;
%put NOTE: name&name_count=&&name&name_count; * almost same as prev;
When dealing with the 'name' of the macro array in 1-level abstraction way, complete resolution is achieved by coding the 'tricky triple-hat' &&&
%macro log_macroArray (basename);
%local i count_symbol value_symbol;
%let count_symbol = &basename._count;
%do i = 1 %to &&&count_symbol;
%let value_symbol = &basename.&i;
%put NOTE: &value_symbol=&&&value_symbol;
%end;
%mend;
%log_macroArray(name);
The SAS macro system 'loops' internally during its value resolution phase and collapses the presence to && to & at each step of it's internal evaluation.
Building on #zuluk's answer, you cannot use an operator (like { }) to access a macro "array" since it's not a part of the language and it's not possible to overload operators in SAS... mostly ... but you can do a function-style macro easily.
proc sql;
select name into :namelist separated by ' '
from sashelp.class;
quit;
%macro marray(list, n);
%scan(&list.,&n.)
%mend marray;
%put %marray(&namelist,2);
That is pretty close to what you're looking for, just not quite the same syntax. If you then wanted to build new variables/etc., you could do so through the macro as well, though it might be more complicated to write a general macro given there are lots of ways you might want to do that. Here's a non-function-style version.
%macro m_to_array(list, n);
*optionally - if you want to not specify n;
%let n = %sysfunc(countw(&&&list));
%do _i = 1 %to &n;
%global &list.&_i.;
%let &list.&_i. = %scan(&&&list.,&_i.);
%end;
%mend m_to_array;
%m_to_array(namelist);
%put _global_;
I have the following piece of code that works, but I'd like to know if anyone can come up with a better way of 'removing' the %nrquote. I have had to add a %SUBSTR function, which works, but I'm keen to know if there are any other suggestions, and if anyone can help explain why the code doesn't work without the %let statement within the mvar macro definition.
/* Automatically generated by DI Studio - cannot change */
%let _where_clause = %nrquote(name = %'Henry%');
%let _mac1 = %nrquote(lemk);
%let _variable = weight;
%let _input0 = sashelp.class;
/* End of auto-generated code */
options mprint;
%macro mvar;
%if &_where_clause ^= %then %do;
/* Re-assign the _where_clause variable to 'remove' %nrquote */
%let _where_clause = %substr(&_where_clause,1);
where &_where_clause
%end;
%mend mvar;
proc sql;
select &_variable into :&_mac1
from &_input0
%mvar
;
quit;
Without the %let statement, the code fails with this error:
NOTE: Line generated by the macro variable "_WHERE_CLAUSE".
1 name = 'Henry'
-
22
MPRINT(MVAR): where name = '
NOTE: Line generated by the macro variable "_WHERE_CLAUSE".
1 name = 'Henry'
-
200
ERROR 22-322: Syntax error, expecting one of the following: a name, a quoted string,
a numeric constant, a datetime constant, a missing value, (, *, +, -, ALL, ANY,
BTRIM, CALCULATED, CASE, INPUT, PUT, SELECT, SOME, SUBSTRING, TRANSLATE, USER.
ERROR 200-322: The symbol is not recognized and will be ignored.
114 ;
MPRINT(MVAR): Henry'
You need %UNQUOTE which is what is happening with %LET, it is un-quoting the quoted quotes.
Change
where &_where_clause
to
where %unquote(&_where_clause)
I am trying to run a program with a prompt for a date in Enterprise Guide. I have the prompt configured, and it appears when I run the program. At the top of the program log I get the following lines that seem to show the macro values for the prompt are populating correctly:
7 %LET Processing_Month_end = 30Nov2015;
8 %LET Processing_Month = 01Nov2015;
9 %LET Processing_Month_label = November 2015;
My question is how to use these macro values as a date later in my program. If I try a simple data step:
data dates;
refDate = &Processing_Month;
run;
I get the following error:
24 GOPTIONS ACCESSIBLE;
25 data dates;
26 refDate = &Processing_Month;
NOTE: Line generated by the macro variable "PROCESSING_MONTH".
26 01Nov2015
_______
22
ERROR 22-322: Syntax error, expecting one of the following: !, !!, &, *, **, +, -, /, <, <=, <>, =, >, ><, >=, AND, EQ, GE, GT, IN,
LE, LT, MAX, MIN, NE, NG, NL, NOTIN, OR, ^=, |, ||, ~=.
27 run;
If I try to use input to format the value into a date:
data dates;
refDate = input(&Processing_Month, date9.);
run;
I get a similar error:
24 GOPTIONS ACCESSIBLE;
25 data dates;
26 refDate = input(&Processing_Month, date9.);
NOTE: Line generated by the macro variable "PROCESSING_MONTH".
26 01Nov2015
_______
22
ERROR 22-322: Syntax error, expecting one of the following: !, !!, &, *, **, +, -, /, <, <=, <>, =, >, ><, >=, AND, EQ, GE, GT, IN,
LE, LT, MAX, MIN, NE, NG, NL, NOTIN, OR, ^=, |, ||, ~=.
27 run;
If I try to wrap the macro value in a date literal:
data dates;
refDate = '&Processing_Month'd;
run;
Error:
24 GOPTIONS ACCESSIBLE;
25 data dates;
26 refDate = '&Processing_Month'd;
____________________
77
ERROR: Invalid date/time/datetime constant '&Processing_Month'd.
ERROR 77-185: Invalid number conversion on '&Processing_Month'd.
27 run;
What syntax or function do I need to use with this prompt macro variable for it to function as a sas date?
You're almost there. Date literal is the right answer, except you're missing one thing: '&mvar.' won't resolve, only "&mvar." will resolve. So switch to double quotes and trailing d, and you'll be right.
data dates;
refdate = "&processing_month."d;
run;
I need to create a prompt. Actually I created another two with no problem, but one of the variable is different while I was creating prompt. I needed to do macro with that as below:
%macro param_list;
%global
list_selected
;
%let i=1;
%let p_lst_tmp = %scan(&VID,&i);
%do %while(&p_lst_tmp ne);
%let list_selected = &list_selected "%scan(&VID,&i)";
%let i = %eval(&i+1);
%let p_lst_tmp = %scan(&VID,&i);
%end;
%put list_selected = &list_selected;
%mend;
Then in the code I created
PROC SQL;
CREATE TABLE Student_Pre AS
SELECT t1.personid LABEL="PIDM" AS PIDM,
t1.V_ID as VID,
t1.FIRST_NAME
FROM ENROLL.Student_Dim t1
WHERE t1.v_id = &list_selected
ORDER BY t1.personid;
QUIT;
But this code gives an error, ERROR 22-322: Syntax error, expecting one of the following: ;, !, !!, &, (, , *, +, -, '.', /, <, <=, <>, =, >, >=, AND, EQ, EQT, EXCEPT, GE, GET, GROUP, GT, GTT, HAVING, INTERSECT, LE, LET,
LT, LTT, NE, NET, NOT, OR, ORDER, OUTER, UNION, ^, ^=, |, ||, ~, ~=.
ERROR 76-322: Syntax error, statement will be ignored.
How should I change the code?