I am not sure if I get any answer on a saturday evening, but I will give a shout :)
I am trying to automize a SAS-code which does comparison in a viariable between 2-3 companies. In each task, I will probably work with different companies, so I guess I can only enter the company names manually.
I describe macro-variables for each company, for example:
%let C1=CompanyNo1; %let C2=CompanyNo2; %let C3=CompanyNo3;
and then I only put &C1 in the remaining code. If I work for another company no later, then I only change the CompanyNo1 in the code.
However, the problem is that I may need to do the comparison between different number of companies later. If I write the code for 4 companies, and if I need to do the comparison between 2 companies in the next run, then I have to deactivate some part of the code.
So I want to write an existince check in the code like;
data _null_;
if &C3 is true then continue the run;
else if quit the code.
run;
Someone told me that I can do that with %Macro statement(he said maybe, he wasn't sure). But I am not sure how to achieve this with %Macro.
Thanks for any contribution in advance...
You can check for existence of macro variables in your code with the %SYMEXIST macro function and SYMEXIST data step function.
Finally I found an effective solution.
%Macro checking;
%let C3=CompanyNo3;
%if &SYSERR > 0 %then %do;
%goto exit;
%end;
'other data processes here';
%exit: /* Be careful, it is not semicolon */
%Mend;
So if there is no CompanyNo3, then SAS gives only a warning that CompanyNo3 is not attended. Then it goes to exit, it doesn't do other data processes. It finalizes the process without error message.
Related
Just for the debugging purpose: Is there a way to stop executing a series of submitted statements on the first error?
Let's say, I have three steps of code where the second statement has an error. Assume that I run all of them at once in the SAS window. Then, I expect SAS to successfully execute the first sentence and to stop working due to the error detected in the second sentence. Then I can easily go there to fix this.
But what's actually happening is that SAS tries to execute all three steps (i.e., 1st, 2nd (with error, though), and 3th). Hope that there is a solution for this.
Two remarks:
I found that the below code may help, but it didn't actually. Otherwise, please enlighten me.
options syntaxcheck dmssynchk;
I don't want to use the SAS option, errorabend because it shuts down SAS session itself. I just want my SAS stop "the submitted code" and want to fix the issue.
Thanks in advance.
There is a commonly used macro called %runquit that allows that... Not sure where it originates from, but here it goes:
%macro runquit;
; run; quit;
%if &syserr. ne 0 %then %do;
%abort cancel;
%end;
%mend runquit;
proc sort data=asdasd;
by _all_;
%runquit;
data abc;
a = 1;
b = 2;
c = 3;
%runquit;
The drawback is that you have to replace any run; or quit; statement with the call to %runquit, making the code less pretty.
A related StackOverflow question can be found here.
Also, see this discussion for other solutions.
Using SAS I'm pulling data from a SQL data base using a pass through for speed as the DB's are quite large. The below code works as expected.
%let expectdate1 = '2013-07-03';*/
proc sql;
connect to ***** as abc (tdpid=***** user='****' password='*****' );
create table Searched_data as
select * from connection to dss(
SELECT *
FROM database.tablename
WHERE CAPTURE_DT >= '2013-07-01' and CAPTURE_DT <= &expectdate1
);
disconnect from abc;
quit;
The issues arises when I wan to have expectate1 parameterised.
so I replace
%let expectdate1 = '2013-07-03';*/
with
%let expectdate1 = put(Date(),YYMMDD10.);
This doesnt work and the error Im getting is something like
....WHERE CAPTURE_DT >= '2013-07-01' and CAPTURE_DT <= put(Date(),YYMMDD10) .....
So its not evaluating my date code and instead its passing the actual code to SQL and not the resultant string.
Shorack is correct that the PUT statement can not be used with %SYSFUNC, however you can use PUTN successfully.
You should simply need the following.
%LET EXPECTDATE1 = %SYSFUNC(PUTN(%SYSFUNC(DATE()),YYMMDD10.));
%put EXPECTDATE1=&EXPECTDATE1.;
SASLOG:
EXPECTDATE1=2013-08-05
Note: edited for the single quotes you need.
Let me first provide a solution that works, then explain why your approach does not work.
Use this piece of code instead:
data _NULL_;
call symput("expectdate1",cats("'",put(Date(),YYMMDD10.)),"'");
run;
The above piece of code will create your string and then put it into the expectdate1 macro variable.
So, why was your code not working?
That is because you do not make a distinction between SAS functions and SAS macro functions.
put(Date(),YYMMDD10.) are not macro functions (easily distinguished because they start with a percentage sign. -> % <-)
So SAS Macro does not evaluate it and just puts the piece of code into your SQL statement, literally.
Now there is something called the %sysfunc function. It is a macro function that will perform the enclosed normal function.
So %sysfunc(Date()) would be resolved by SAS macro before setting the macro variable expectdate.
Note that each function needs to be enclosed by the %sysfunc function, i.e.,
%let someVariable = %sysfunc(mean(max(1,3),5)); /*WRONG*/
%let someVariable = %sysfunc(mean(%sysfunc(max(1,3)),5)); /*RIGHT*/
That being said, it does not work for some SAS functions and put is one of them. That is why i provided the solution on top: use a data step to prepare it any way you like and write the result into a macro variable.
I am looking for a way to create a string variable containing certain values of the dataset while going through the data step.
Example data set work.test:
AddToStringYN Value
Y One
Y Two
N Three
Y Four
N Five
So in the end, the variable would look like: OneTwoFour (or even better FourTwoOne).
This looks so simple, but I can't seem to find a way to do it.
I also tried to work with macro variables like this:
%let stringvar=;
Data _null_;
set work.test;
if AddToStringYN = "Y" then do;
call symput('stringvar',"&stringvar" || strip(value));
end;
Run;
But this gives:
GLOBAL STRINGVAR Four
So I only get the last value. I get that this must be because of some misunderstanding of mine about this macro facility, but I don't understand why there is only the last value in the variable.
I thought it was only the last time the symput was called that it was actually executed or something, but then when I adjust the code to:
%let stringvar=;
Data _null_;
set work.test;
if AddToStringYN = "Y" then do;
call symput('stringvar'||strip(value),"&stringvar" || strip(value));
end;
Run;
Then I do get them all:
GLOBAL STRINGVARONE One
GLOBAL STRINGVARTWO Two
GLOBAL STRINGVARFOUR Four
So my last guess is that going through the data step, the 'call symput...' line is actually added to the macro processor where the "&stringvar" is already replaced and only after the final statement are they all executed.
Is this a good assumption or is there another explanation?
And back to the original question: is there an easy way to achieve this (having the desired variable)?
The following is my answer to your identical question on RunSubmit.com. I think you and #Fabio may be over-engineering the solution, it doesn't need any iterating data step code at all...
First, the easy way to do what you're trying to do is like this:
proc sql;
select Value into :StringVar separated by ''
from work.test
where AddToStringYN='Y'
;
quit;
Here, you can take advantage of the SQL interface with SAS/MACRO, using the select into syntax. You could even add an order by clause to get a particular order you're looking for.
Second, since you've happened upon something about the way SAS macro works and you're keen to understand it: in your first example, the first thing the compiler does before executing your code is to resolve the value of &stringvar, which at that point is empty. So after compilation, with this token replaced, your code looks like this to SAS...
%let stringvar=;
Data _null_;
set work.test;
if AddToStringYN = "Y" then do;
call symput('stringvar',"" || strip(value));
end;
Run;
...then SAS goes ahead and runs that code (which happens to be valid code, but is concatenating an empty string to the start of something). And because of the way the data step works, each iteration of the data step is in fact replacing the value of StringVar, which is why at the end of the data step, it's left with the last value that was read in.
Greetings
Seems simple enough, here is my solution:
data a;
set test end=eof;
length cat $100.;
retain cat;
if AddToStringYN = "Y" then do;
cat=trim(left(cat))||trim(left(value));
end;
if eof then do;
call symput("VAR",cat);
output;
end;
run;
%put VAR=&VAR;
in this example you have the concatenation of your variable in the A dataset in the column "CAT" and you have a macrovariable VAR with the same list
I copy the code from a paper that i found on internet.
proc fcmp outlib=work.funcs.Test;
function whatAmI();
return(42);
endsub;
quit;
options cmplib=work.funcs;
data _null_;
rci = whatAmI();
put rci=; /* should be 42 */
run;
When I execute the code, it show the message:
ERROR 68-185: The function WHATAMI is unknown, or cannot be accessed.
I tried other functions and always show this message.
I change the libname, but nothing work.
What´s wrong?
I agree with Aditya.
Seems like 9.2 has the ability to actually use functions, while 9.1.3 only has the ability to more or less create them.
Check out THIS THREAD for more info.
Looks like a problem with the version. Make sure you are using SAS 9.2, since previous versions have a limited support of PROC FCMP.
I'm creating a 2-column report in SAS using PROC REPORT inside the ODS PDF statement.
My code looks something like this:
ods pdf file='/file/here.pdf' columns=2;
ods pagestart=now;
proc report data=rpt\_data nowd missing contents='';
columns a b c;
by a;
define a /group order=internal;
define b /display;
define c /display;
break after a /page;
run;
This only seems to "break" to the next column on the page, rather than an actual new page like I would like it to.
Any suggestions?
Running this code will produce the issue I'm inquiring about.
%let file1='/file/directory/test.pdf';
ods pdf file=&file1. columns=2;
ods pdf startpage=now;
proc sort data=sashelp.class out=temp;
by age;
run;
proc report data=temp nowd missing contents='';
columns age name sex;
by age;
define age /group order=internal;
define name /display;
define sex /display;
break after age /page;
run;
ods \_all\_ close;
As far as I know, this is not yet possible for the ods pdf destination as of 9.2. That is, without very ugly hacks like adding ghost rows to the short by-group and coloring them with the background color so that they are invisible on paper, and so on. SAS's technical support is quite responsive. I would call/email them before I give up, though. Hope this helps a bit.
This might not be practical in your case, but just in case: You can set page breaks if you use the ODS "Measured RTF" destination ; then you could convert your RTF file to a pdf...