Trouble with field-input accepting single quotes for %windows in SAS - sas

I have the following code where users will be presented with the following window and they are to enter a text
Code:
%let study_code=;
%macro startme ;
%global study_code;
%window first
#3 #45 'Electronic Filing System' color=blue ////
#20 'Study code:' color=black +2 study_code 30 color=green required=yes attr=underline //
#10 '**************** Hit ENTER to begin ******************' color=green
;
%display first ;
%let study_code_new=%sysfunc(strip(%nrbquote(&study_code)));
%put &study_code_new.;
%mend;
%startme;
Window presented when run:
I type 123, hit Enter and it outputs 123 in the logs as expected:
However, if a user enters 123" by accident in the field, I am presented with the single quote error:
ERROR: Literal contains unmatched quote.
ERROR: The macro STARTME will stop executing.
How do I prevent SAS from reading " as code and treat it as literal string? I want to capture it in study_code_new macro variable so that I can tell the user that they have mistyped it.

It is not the %WINDOW command or the %DISPLAY command that is the issue. It is the code that you write that uses the macro variable's value. You need to add macro quoting.
So first immediately add macro quoting to the macro variable populated by the %DISPLAY statement call.
%window first
#3 #45 'Electronic Filing System' color=blue
#7 #20 'Study code:' color=black +2 study_code 30 color=green
required=yes attr=underline
#9 #10 '**************** Hit ENTER to begin ******************' color=green
;
%display first ;
%let study_code=%superq(study_code);
Then make sure to keep the macro quoting on any macro variable you derive from it (at least until you are sure it no longer needs the macro quoting).
46 %window first
47 #3 #45 'Electronic Filing System' color=blue
48 #7 #20 'Study code:' color=black +2 study_code 30 color=green required=yes attr=underline
49 #9 #10 '**************** Hit ENTER to begin ******************' color=green
50 ;
51 %display first ;
52 %let study_code=%superq(study_code);
53 %let study_code_new=%qsysfunc(strip(&study_code));
54 %put &=study_code &=study_code_new;
STUDY_CODE= 123" STUDY_CODE_NEW=123"

Related

Combine two SAS datasets into one .dat file

I have two datasets in two different SAS tables that also have completely different data structures. I am being asked (not my idea) to export these datasets to one .dat file and essentially stack them on top of each other using a fixed width method. The below listed snippet of data is how the export should ultimately look when it gets to the .dat file. The first row is the result of the first dataset. The second row is result of the second dataset.
UH INCR000000XXXXXXXXXXXXXXXX
XXX SFLXXXXXXXXXXXX 000 M SMITH XXXXXX XXXXXXXXXXXXX9991231
I cant figure out exactly how to do this. Below is the code I've come up with that exports the data but the second data step just overwrites the first.
Here's an example using the MOD option on the FILE statement.
Note this may not work on all OS's.
filename test1 '/home/reeza/Demo1/testfile.dat';
data exportClass;
set sashelp.class;
file test1;
if _n_=1 then do;
put #1 "Name" #20 "Age" #30 "Sex";
end;
put #1 Name #20 Age #30 Sex;
run;
data exportClass;
set sashelp.class;
file test1 mod;
if _n_=1 then do;
put #1 "Name" #20 "Weight" #30 "Height";
end;
put #1 Name #20 Weight #30 Height;
run;
filename test1;

Macro Automization via Prompts in SAS EG

here is my table
data:
ax bx cx dx ex fx
1 2 3 4 5 5
2 3 5 1 0 5
3 7 8 9 1 4
here is my basic code
%macro example(c= , b= ,a= );
data temp;
set data;
diff = &c-(&b+&a);
run;
%mend example;
% example(c=cx ,b=bx ,a=ax)
I want to automize diff = c-(b+a) by setting a prompt-like feature in SAS EG but I do not know how to do it? My aim is to be able change my features(for example instead cx, I want to put f or instead ax,e and so on) in "diff" equation because my actual data consists of thousands of columns.
If you help me, I appreciate.
To automate this, you'd probably want to make three prompts. One for each variable (c,b,a). (Of course, call them something descriptive, not c,b,a!) Select "use throughout project" and "requires non blank value". Maybe add some more useful text to describe what they are.
Then, you need to have a way of populating them. You can either populate them from a static list (enter the possible values in), just as open text boxes where you'll type them in yourself each time, or you can populate them from a data source. The mechanics of populating from a data source depends on your local setup - are you using "local EG" or is it EG connected to a metadata server, for example - but overall it should be fairly straightforward.
Either on "User selects values from a static list", select "Get values", then "Browse" for the SAS data file; or "User selects values from a dynamic list", do the same. The latter will always check the data source for updates, while the former just populates the list at prompt creation time.
Finally, in your program, your macro call would then look like:
%example(c=&c ,b=&b ,a=&a)
where &c &b &a are the prompt names (the 'short' name if you gave it a longer text name also).
What you want is something like this:
/*Define Prompt*/
%window info
#5 #5 'Var1:'
#5 #13 var1 2 attr=underline
#7 #5 'Var2:'
#7 #13 Var2 2 attr=underline
#9 #5 'Var3:'
#9 #13 Var3 2 attr=underline;
/*Show Prompt*/
%display info;
/*Display Macro Variables in the Log*/
%put &var1;
%put &var2;
%put &var3;
%example(c=&var1 ,b=&var2 ,a=&var3)

How to add input box to sas sql query which ask user about parameter?

How to add input box to sas sql query which ask user about parameter ? (Something aka Access input box) (in Enterprise Guide)
Here is a solution using BASE -
You could use the %Window procedure with the %display
DATA _NULL_;
%LET BATCH1=;
%WINDOW BATCH_ANALYSIS COLOR = WHITE
ICOLUMN = 30 IROW = 11
COLUMNS = 88 ROWS = 20
#1 #28 "CLIENT BATCH REPORT"
#4 #12 "Date must be entered YYYY-MM-DD Format, ascending order."
#6 #28 "Example = '2015-01-31'"
#9 #5 "Enter Batch Date - [ENTER] when complete:"
#11 #5 BATCH1 12 attr=underline
#13 #5 "Reports will be written to 'location'";
%DISPLAY BATCH_ANALYSIS;
STOP;
RUN;
%put %batch1;
This above is an example of using the "user input" to operate on your query/data step. In this case, I am prompting the user to enter a date, which creates that string value as a macro variable that can be passed anywhere in your SAS code (I am only using the string date format because it gets passed to an RSUBMIT in a DB2 environment). May be a good idea to play with the Input Lines/etc to display the text you want in your prompt window...
Are you using Enterprise Guide?
If thats the case, you can create prompts which will create macro variables when you run your code.
You will just have to use those macro variables in your code.
Right click your program > Properties > Prompts > Prompt Manager and so on.
Have a look at it and see if it solves your problem.

Clear inputs from SAS %Window function

I am using SAS version 9.2 and have the following piece of code that aborts a job run through based upon some conditional input from the end user:
%WINDOW flowmng
ICOLUMN= 15 IROW= 10
COLUMNS= 80 ROWS= 20
"<Have you checked that all three Flow Manager jobs have completed successfully?>"
#5 #15 "Type 'Yes' for yes or 'No' for no, THEN press
[ENTER]"
#9 #23 "Flow Manager jobs run?" #48 resp 3
ATTR=UNDERLINE REQUIRED=YES
;
%MACRO macronam ;
%LET null = ;
%LET resp2 = %UPCASE(&resp);
%DISPLAY flowmng ;
%IF (&resp2 eq YES) %THEN %DO;
%END;
%IF (&resp2 eq NO) %THEN %DO ;
%ABORT;
%END ;
%MEND macronam ;
%macronam;
This all works great apart from the fact that when I reopen the window, the user input from the last job is still there. I've tried looking for the %WINDOW option to reset all fields, but I cannot seem to find it in the documentation I have read.
Does anyone have the syntax for this?
Thanks
It's using the value of &resp, so just add
%let resp=;
before the %WINDOW call.

SAS questions - Can't read the numeric column of this dataset

I have a blood.txt dataset like this (first 5 obs):
1 Female AB Young 7710 7.4 258
2 Male AB Old 6560 4.7 .
3 Male A Young 5690 7.53 184
4 Male B Old 6680 6.85 .
5 Male A Young . 7.72 187
I used the following program to read it:
data blood_sum;
infile "/path/blood.txt";
input #1 SubjID $
#6 Gender $
#13 BloodType $
#16 AgeGrp $
#22 RBC
#29 WBC
#34 Cholesterol ;
run;
But the last column "Cholesterol" can't display; all values are replaced by "." My log has numerous NOTE errors like this:
NOTE: Invalid data for Cholesterol in line 1 34-37.
RULE: ----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0
1 CHAR 1 Female AB Young 7710 7.4 258. 37
ZONE 3222246666624425676623333222323223330
NUMR 1000065D1C501209F5E7077100007E400258D
SubjID=1 Gender=Female BloodType=AB AgeGrp=Young RBC=7710 WBC=7.4 Cholesterol=. _ERROR_=1
Can anyone help?
I'm going to guess that you are running this on a UNIX system but the file you are reading (blood.txt) was created on a Windows system and copied to your system in binary mode.
If you look at the log, you should notice there is a "dot" after the last value in your input line (in column 37). The ZONE and NUMR parts of the display reveal the hex code for that position, in this case '0D', which is a carriage return character. If you open the file with a UNIX editor (like vi), you will see those characters represented as ^M at the end of each line.
You can either download a fresh copy from where ever you received it (making sure to transfer the file in TEXT mode) or you can convert your copy to a UNIX text file. To convert, you can use the dos2unix command like this:
dos2unix /path/blood.txt /path/blood.txt
Note that if you use the same name it will overwrite the original file. Of course, I assume you have permission to do that.
In case you cannot convert the file for some reason, you can use a pipe to do the conversion. In other words, use this FILENAME statement and change your INFILE statement to read from the filename:
filename mydata pipe "tr -d '\r' < /path/blood.txt";
data blood_sum;
infile mydata truncover;
input #1 SubjID $
#6 Gender $
#13 BloodType $
#16 AgeGrp $
#22 RBC
#29 WBC
#34 Cholesterol ;
run;
I added the truncover option although you may not need it. Read more about it in the docs if interested.
By the way, this is a very common error and happens to everyone at least once. Welcome to StackOverflow.
I'll give a slightly different solution for the problem, which I agree with Bob is caused by the carriage return at the end of the line.
You can control the terminating character for a line (normally, for Windows, CR/LF or '0d'x '0a'x ; for Unix, '0a'x or LF only) with the TERMSTR option on the infile.
http://support.sas.com/kb/14/178.html
data blood_sum;
infile "/path/blood.txt" termstr=CRLF;
input #1 SubjID $
#6 Gender $
#13 BloodType $
#16 AgeGrp $
#22 RBC
#29 WBC
#34 Cholesterol ;
run;
By the way, I find your input method a bit confusing. You're sort of mixing input types here, so you might not always get consistent results. In fact, this probably would've never happened if you had explicitly assigned the formats!
input
#1 subjid $4.
#6 gender $6.
#13 bloodtype $2.
#16 agegrp $5.
#22 rbc best8.
#29 wbc best4.
#34 Cholesterol 3.
;
Then Choleserol would be read from 34-36 and you would've never had SAS trying to include 37 in the variable.