I am trying to use the %Dropmiss Macro in sas, which I found from an official PDF https://support.sas.com/resources/papers/proceedings10/048-2010.pdf
however, when I try to use it, I always get the same error:
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:
"%qtrim(&&CHARMAX&I)" eq ""
Being a newbie in Macros, I have tried to find a solution everywhere , but nothing so far. What is possibly the problem? What should I do or check in my data to fix the problem.
Thank you,
Not sure about your macro but you don't need a macro. That paper is a decade old so here's a more modern approach.
ods select none;
ods output nlevels=temp;
proc freq data=have nlevels;
tables _all_;
run;
proc sql;
select tablevar into : drop separated by ','
from temp
where NNonMissLevels=0;
alter table data&i
drop &drop;
quit;
Original source, since not my code:
https://communities.sas.com/t5/SAS-Programming/deleting-empty-columns/m-p/308045
Related
I'm having basically the same issue as the following post:Proc Data sets argument error- Error 22-322 expecting a name
But the answer didn't solve my problem.
%let _EFIERR_ = 0; /* set the ERROR detection macro variable */
libname indata "E:\el30053_54_55\el30053-postprocessor\output\files";
/* Format HYPO1001 variables */
PROC datasets library=INDATA;
MODIFY INDATA.hypo1001
/* Format section. */
format HYPOR1;
/* Should not need to edit anything below. */
run;
quit;`
Essentially, I have several datasets in the library INDATA. One of them is called hypo1001. Bottom line, I need to rename some of the variables in the dataset, but the rename statement isn't working because there are a few variables with invalid formats. So now I'm trying to fix the formats, but it doesn't seem to be working. From what I can tell, my syntax is correct, but I have very limited experience with SAS that doesn't usually extend much beyond just converting xpt files to SAS format.
I'm getting the following errors in the log:
ERROR 22-322: Expecting a name.
ERROR 201-322: The option is not recognized and will be ignored.
The libref you used to define the library should not be included in the member name that you use in the MODIFY statement. Try this example:
data class; set sashelp.class; run;
proc datasets nolist lib=work;
modify class ;
format name ;
run;
quit;
We currently use the %runquit macro function as detailed here (http://analytics.ncsu.edu/sesug/2010/CC07.Blanchette.pdf). The %runquit macro is shown below. It basically stops running any more SAS code when an error is encounterd, and can be used as a replacement for both the run and quit statements:
%macro runquit;
; run; quit;
%if &syserr %then %abort cancel;
%mend;
Because using the outobs statement in proc sql triggers a system error (even when the nowarn option is specified) it means we are unable to use the %runquit macro when we need to use the outobs= option.
The below example will generate the following warning message:
proc sql noprint outobs=3 /*nowarn*/;
create table tmp as
select age, count(*) as freq
from sashelp.class
group by 1
order by 2 desc
;
%runquit;
WARNING: Statement terminated early due to OUTOBS=3 option.
Thank you SAS for the completely unnecessary warning. The behaviour is obviously expected because I explicitly wrote code to ask for it. I don't see warnings given when we specify inobs= and outobs= on a set statement. Why does proc sql get the special treatment?
Is there any way to disable the warning issues by the outobs= option in proc sql? Alternatively, is there another way to limit the output rows from proc sql that will not generate an error?
Assuming you are okay with the full SQL statement executing, you can get around this with a data step view that contains the obs limitation.
proc sql noprint ;
create table tmp as
select age, count(*) as freq
from sashelp.class
group by 1
order by 2 desc
;
%runquit;
data tmp_fin/view=tmp_fin;
set tmp(obs=3);
%runquit;
Or make the SQL statement a view and use the data step to make the data set.
proc sql noprint ;
create view tmp_view as
select age
, count(*) as freq
from sashelp.class
group by 1
order by 2 desc
;
quit;
data tmp;
set tmp_view(obs=3) ;
run;
This might be one of your options considering I/O is not a huge constraint, here the reset outobs= option with nowarn does the trick but at IOs cost.
proc sql;
create table test as
select * from sashelp.class;
reset outobs=10 nowarn;
create table test1 as
select * from sashelp.class;
quit;
I am very new using SAS and Im having hard time trying to assign the output value of a function-like macro to a macro variable. After testing, I have check that the value is computed correctly, but once I tried to assign it the program crashes. here you can find the code
%MACRO TP_BULLET(ZCURVE,TAU,YF=1);
/* KEEP ONLY THE ZERO CURVE UNTIL MATURITY*/
DATA _TEMP;
SET &ZCURVE;
IF MATURITY > &TAU THEN DELETE;
RUN;
PROC SQL NOPRINT;
SELECT DISTINCT 1- DF
INTO :NUME
FROM _TEMP
GROUP BY MATURITY
HAVING MATURITY = MAX(MATURITY);
QUIT;
PROC SQL NOPRINT;
SELECT SUM(DF)
INTO :DENO
FROM _TEMP;
QUIT;
PROC DELETE DATA=_TEMP;RUN;
%LET TP = %SYSEVALF(&YF*&NUME / &DENO);
&TP
%MEND TP_BULLET;
%MACRO TESTER2;
%LET K = %TP_BULLET(ZCURVE,TAU,YF=1);
%PUT .......&K;
%MEND TESTER2;
%TESTER2;
The error I am getting is the following
WARNING: Apparent symbolic reference DENO not resolved.
WARNING: Apparent symbolic reference NUME not resolved.
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:
1*&NUME / &DENO
So I suppose that the DATA Step is failing to create the sas table _TEMP, but I have no idea how to solve it. Thanks in advance for any help or sugestion
This is NOT a 'function like' macro - you are mixing SAS Macro language and Base SAS. Remember that the SAS Macro language is a code generator - and you are generating code, which is currently something like:
%let K=data _temp; set ZCURVE; ....
note how the above is not what you wanted to assign to the macro variable K.
To help with this, try running your macro with options mprint - this will show you the code being generated by your macro.
If you want your macro to act like a function, then (at a minimum) you should find NO code being generated via the mprint option..
All philosophical issues aside, you could add a parameter to your macro that specifies the new macrovariable (mv) that you want to create. So instead of
%Let k = %TP_BULLET(ZCURVE,TAU,YF=1);
you could call
%TP_BULLET(ZCURVE,TAU,mvOutput=k,YF=1);;
Your macro would need to be modified slightly with
%MACRO TP_BULLET(ZCURVE,TAU,mvOutput,YF=1);
%GLOBAL &mvOutput;
........ Same code as above .........
%Let &mvOutput = &TP; *Instead of final line with '&TP';
%MEND;
It is not a very SAS-y way to accomplish it, but it can help keep things more modular and comprehensible if you're working with more programming backgrounds, rather than SAS.
I am trying to determine the number of observations in a dataset, then convert this number into a macro variable that i can use as part of a loop. I've searched the web for answers and not had much luck. I would post some example code I've tried but I have literally no idea how to approach this.
Could anybody assist?
Thanks
Chris
SAS stores dataset information, such as number of observations, separately, so the key is to access this information without having to read in the entire dataset.
The following code will do just that, the if 0 part is never true so the dataset isn't read, however the information is.
data _null_;
if 0 then set sashelp.class nobs=n;
call symput('numobs',n);
stop;
run;
%put n=&numobs;
You can also get it from dictionary.tables like this:
proc sql noprint;
select nobs into :nobs
from dictionary.tables
where libname='YourLibrary' and memname='YourDatasetName';
quit;
Here it is:
Create macro variable:
data _null_;
set sashelp.class;
call symput("nbobs",_N_);
run;
See result:
%put &nbobs;
Use it:
data test;
do i = 1 to &nbobs;
put i;
end;
run;
Executing locally in a clean session:
%let x = %str(put(age, best.));
proc sql;
select &x from sashelp.class;
quit;
This generates the following error:
1 put(age, best.)
----
22
----
76
ERROR 22-322: Syntax error, expecting one of the following: a format name, ?.
ERROR 76-322: Syntax error, statement will be ignored.
But this "manually-resolved" version runs without notes, warnings or errors:
proc sql;
select put(age, best.) from sashelp.class;
quit;
Can somebody explain exactly what %str() is doing in this program that causes an issue at execution time? Apologies for the vague question, but I am unsure what the relevant interactions are; I cannot replicate using equivalent data-step syntax so perhaps proc SQL peculiarities are involved?
The %str() function masks a character string during macro compilation. Remove the %str() function in the let statement or add an %unquote() function in the sql select to have if resolve correctly.
Answered at this question on runsubmit.com:
I'm going to mark this answer as
correct because it led me to this page
of documentation:
http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/viewer.htm#tw3514-unquote.htm
- "In rare cases, masking text with a macro quoting function changes the way
the word scanner tokenizes the text
... The word scanner does not use it
as the boundary of a literal token in
the input stack". Sounds like a bug,
frankly, but if the tokenizer
algorithm is as ancient and hairy as I
imagine, I'd spin it as a quirk too!
Can you use a format statement instead? For example, this works just fine.
%let x = %str( age format=best.);
proc sql;
select &x. from sashelp.class;
quit;
For some reason SAS doesn't like the "best." format.
i.e. when I try this, your code works
%let x = %str(put(age, 8.));
????
If you add this to your code
%put _user_ ;
you will see how &x is quoted by %str, in the log. That is why the proc sql code doesn't work. Using %Unquote in the select portion of the proc sql statement will allow the code to run.
http://www2.sas.com/proceedings/forum2007/152-2007.pdf