Discover More Tips and Techniques on This Blog

MedDRA and WHODrug Coding

Though there are other Coding dictionaries available along with MedDRA (ex: COSTART and WHOART), MedDRA dictionary is typically used in the US for Adverse Events coding.

AE\MedDRA coding is not the SAS programmers work; it is usually done by medical coder or database programmer. Coding basically involves a process of finding a dictionary term that matches the verbatim term reported on the CRF, and getting the other related dictionary derived variables useful for the analysis like System Organ Class (SOC), Preferred Term (PT) and Lowest Level Term (LLT), etc.

Some times this process may take more time than expected, because Misspellings and other differences would delay the process of coding. In that case, person responsible for coding has to look for the dictionary term that which is the best possible match from the MedDRA dictionary.

So the question here comes is what SAS programmer can do in this process.

Here is the Answer….

SAS programmer has to work hard to make this process successful. In other words he is also a key player in this game.

SAS Programmer provides a list of reported AE terms on the CRF to the medical coder in a flat file/excel file, who then search for a best possible match and related terms for AE term of CRF in the MedDRA dictionary. He then enters them in the supplied flat/excel file and returns back to the SAS programmer.

The next SAS programmer duty is to assign the Dictionary derived Term, SOC, LLT and PT to the AE Terms in the AE dataset by merging. (Use Proc SQL or Simple Merge)

MedDRA dictionary gets updated twice a year, so it is important to be aware of the version used for the coding.

If the data is clean (Assuming that there are no misspelling of AE terms or other problems then MedDRA coding is easy…. What you have to do is locate the MedDRA SAS dataset and then merge the MedDRA dataset with the AE dataset using the preferred term.
















Making Code Review Painless

ABSTRACT:
Code review is an essential step in the development of concise and accurate SAS® programs. It is a required verification step in performing validation in a regulated environment. This paper will present techniques and a macro that can be freely downloaded to automate this task. The %coderev macro will perform many of the common tasks during a code review including:

1. Spell checking headers and comments
2. Reviewing all input and output datasets of the program
3. Comparing defined macro variables versus macro variable usage
4. Checking for multiple macro calls that are not in a macro library
5. Evaluating hard code logic
6. Evaluating sort order of all datasets

These tasks are normally performed by an independent reviewer instead of the original programmer. By automating the tasks, the code review process will ensure that the smallest mistake can be captured through reports to ensure the highest quality and integrity. What normally is a dreaded task can now be done with ease.
Thanks to Sy Truong, Meta-Xceed, Inc, Fremont, CA

SAS Instructor Tips: Programming

SAS Instructor Tip: Programming

Featured Instructor: Cynthia Johnson

How do I combine my SAS data sets and eliminate duplicate rows at the same time?

SAS Instructor Cynthia Johnson responds ...




SAS Instructor Tip: Programming

Featured Instructor: Kent Reeve

What happens when you forget the period on an informat when using formatted input?




SAS Programming Tips[1]



SAS/GRAPH Tip: Controlling the Graph Axis

SAS Instructor Cynthia Zender shows you how to control the graph axis through a feature of using the AXIS statement.



SAS ODS Tip: Creating Page X of Y Page Numbers
SAS Instructor Cynthia Zender shows you how to use the SAS ODS ESCAPECHAR to create a "Page X of Y Page Numbers"



SAS ODS Tip: Creating a Table of Contents

SAS Instructor Cynthia Zender shows you how to create a table of contents using the CONTENTS= Option with ODS RTF and ODS PDF destinations.



SAS ODS Tip: Controlling the Width of Cells

SAS Instructor Cynthia Zender shows you how to control the width and spacing of cells using STYLE=Overrides that have been designed for the ODS destinations that support STYLE.



SAS Programming Tip: Subsetting Data with a WHERE Statement

SAS Instructor David Ghan shows you how to to use a WHERE statement to subset your data.




What's new in SAS V 9.2 for Base SAS

Listen to the SAS lecture series by http://www.sas.com/ to find out whats new in SAS 9.2 version.....

SAS Lecture series for SAS 9.2 changes and enhancements for Base SAS has 3 sessions:

Session 1: New and enhanced Procedures and Statements
  1. Overview of Changes and Enhancements
  2. DATA step Changes and Enhancements
  3. Base Engine Changes and Enhancements
  4. New Base Procedures
  5. Base Procedures Changes and Enhancements


Session 2: The SAS Macro Facility
Session 3: SAS XML LIBNAME Engine and ODS

Listen to
e-Lecture

---Then




Note: e-lecture is on Session 1 only..


SAS Documenatation: What's New in SAS 9.2

Macro IN Operator

Have you ever come across a situation where you have to write a macro program where a macro variable has more than one value? Writing a macro program in this case involves so many different conditions and to connect each condition you generally use OR operator as below…

%macro test;
%if &dsn=ae or %if &dsn=ds or %if &dsn=co or %if &dsn=cm %then %do; Some---SAS—Statements;
%end;
%test;

You can use a simple IN operator inside the datastep and make the code very simple… like as follows…

data dsn;
set old;
if &dsn in ("ae","ds","co","cm") then do;
Some---SAS—Statements;
end;
run;

Can we use the same IN operator inside the macro…

If you are using any SAS version prior to 9.2 … the answer is.. You cannot use IN operator inside the macro.

But…..

In SAS 9.1.3 version:
You can use character # (new binary comparison operator) as an alternate operator to mnemonic IN operator.

Using # operator in the above code:

%macro test;
%if &dsn # ae ds co cm %then %do;
Some---SAS—Statements;
%end;
%test;

Even if you use it, SAS will give you an ERROR message saying the Operator is not recognized.

In SAS 9.2 version:
You can directly use the IN operator inside your macro code as like in simple datastep in SAS 9.2.

Using IN operator in the above code:

%macro test;
%if &dsn in ae ds co cm %then %do;
Some---SAS—Statements;
%end;
%test;

Note:
No need of % sign in front of IN operator.
In SAS 9.2 both IN and # work if you use the system option minoperator inside your macro call.

In SAS Version 9.2:

%macro test/minoperator;
%if &dsn # ae ds co cm %then %do;
Some---SAS—Statements;
%end;
%test;

%macro test;
%if &dsn in ae ds co cm %then %do;
Some---SAS—Statements;
%end;
%test;


Both works fine…..

MINOPERATOR option tells SAS to recognize the word 'IN' or special symbol # by the SAS macro facility as an infix operator when evaluating logical or integer expressions.


Here is another way of writing the macro code with delimiters.

Use MINDELIMITER option to change the default delimiter from space to any other, in this case it is comma (,).

options mindelimiter;

%macro test/mindelimiter=',';
%if &dsn in ae,ds,co,cm %then %do;
Some---SAS—Statements;
%end;
%test;

Macro Debugging Options:MPRINT, MLOGIC, SYMBOLGEN, MACROGEN, MFILE

Macro Debugging Options:

Debugging a macro code isn’t easy process. It is difficult to identify the problem in the SAS code just by seeing the ERROR message in the LOG file. It is lot easier to debug a macro if we use the following SAS options.

There are four system options that are helpful in debugging SAS Macros:

SYMBOLGEN, MPRINT, MLOGIC, and MFILE.
Each option adds different information to the SAS LOG File.

Like any other SYSTEM OPTIONS, you turn these on using the OPTIONS statement:

Options macrogen symbolgen mlogic mprint mfile;
You can turn them off by specifying the following OPTIONS statement:

Options nomacrogen NoSymbolgen nomlogic nomprint nomfile;


Both statements are needed in side SAS. Once you set any option and it will remain in effect throught the SAS session. So if you want to debug the macro use first OPTIONs Statemnt else use 2nd one.

Let’s look at each option, and the output they produce in more detail…


MPRINT:As we know that when we execute a macro code SAS doesn’t display it in the LOG file, but using the MPRINT option displays all the SAS statements of the resolved macro code.

MPRINT option prints one statement per line along with resolved macro code.

LOG FILE:
31 %macro concat;
32 data all;
33 set
34 %do i = 1 %to 4;
35 dsn&i
36 %end;
37 ;
38 run;
39 %mend;
40 %concat;
MPRINT(CONCAT): data all;
MPRINT(CONCAT): set dsn1 dsn2 dsn3 dsn4 ;


NOTE: There were 6 observations read from the data set WORK.DSN1.
NOTE: There were 6 observations read from the data set WORK.DSN2.
NOTE: There were 6 observations read from the data set WORK.DSN3.
NOTE: There were 6 observations read from the data set WORK.DSN4.
NOTE: The data set WORK.ALL has 24 observations and 1 variables.
NOTE: DATA statement used (Total process time):
real time 0.06 seconds
cpu time 0.06 seconds

MPRINT(CONCAT): run;

Note: Even though we wrote the macro code, the MPRINT option prints the resolved macro code into the LOG file as seen above.


MLOGIC:This option is very helpful when we deal with nested macros (Macro inside another macro). Often we use %DO loops and or %IF-%THEN-%ELSE statements inside the macro code and LOGIC option will display how the macro variable resolved each time in the LOG file as TRUE or FALSE .

To be more specific, MLOGIC option identifies and displays the macro logic. It even follows the macro execution pattern.

LOG FILE:
31 %macro concat;
32 data all;
33 set
34 %do i = 1 %to 4;
35 dsn&i
36 %end;
37 ; /* this additional ';' is necessary, the first ';' is for
38 the "%end", while the second ';' is for "set " */
39 run;
40 %mend;
41
42 %concat;
MLOGIC(CONCAT): Beginning execution.
MLOGIC(CONCAT): %DO loop beginning; index variable I; start value is 1; stop value is 4; by value is
1.
MLOGIC(CONCAT): %DO loop index variable I is now 2; loop will iterate again.
MLOGIC(CONCAT): %DO loop index variable I is now 3; loop will iterate again.
MLOGIC(CONCAT): %DO loop index variable I is now 4; loop will iterate again.
MLOGIC(CONCAT): %DO loop index variable I is now 5; loop will not iterate again.
NOTE: There were 6 observations read from the data set WORK.DSN1.
NOTE: There were 6 observations read from the data set WORK.DSN2.
NOTE: There were 6 observations read from the data set WORK.DSN3.
NOTE: There were 6 observations read from the data set WORK.DSN4.
NOTE: The data set WORK.ALL has 24 observations and 1 variables.
NOTE: DATA statement used (Total process time):
real time 0.06 seconds
cpu time 0.06 seconds

MLOGIC(CONCAT): Ending execution.

SYMBOLGEN:Often we use multiple ampersands (ex: &&dsn.&i) and SYMBOLGEN option prints the message in the LOG file about how the macro variable is resolved.

To be more specific, it prints message in the LOG whenever a macro variable get resolved.

LOG FILE:
31 %macro concat;
32 data all;
33 set
34 %do i = 1 %to 4;
35 dsn&i
36 %end;
37 ; /* this additional ';' is necessary, the first ';' is for
38 the "%end", while the second ';' is for "set " */
39 run;
40 %mend;
41
42 %concat;
SYMBOLGEN: Macro variable I resolves to 1
SYMBOLGEN: Macro variable I resolves to 2
SYMBOLGEN: Macro variable I resolves to 3
SYMBOLGEN: Macro variable I resolves to 4


NOTE: There were 6 observations read from the data set WORK.DSN1.
NOTE: There were 6 observations read from the data set WORK.DSN2.
NOTE: There were 6 observations read from the data set WORK.DSN3.
NOTE: There were 6 observations read from the data set WORK.DSN4.
NOTE: The data set WORK.ALL has 24 observations and 1 variables.
NOTE: DATA statement used (Total process time):
real time 0.06 seconds
cpu time 0.06 seconds


MFILE:
MFILE is useful when we want to create a newfile with the resolved macro code.
To create a newfile you have to specify FILENAME statement as follows:

Filename mprint ‘C:\Users\Sarath Annapareddy\Desktop\macroresol.sas’;
Options mprint mfile;


Note: Whenever the macro code executes, the resultant resolved macro code will be written to the macroresol.sas file.

LOG FILE:

31 %macro concat;
32 data all;
33 set
34 %do i = 1 %to 4;
35 dsn&i
36 %end;
37 ; /* this additional ';' is necessary, the first ';' is for
38 the "%end", while the second ';' is for "set " */
39 run;
40 %mend;
41
42 %concat;
NOTE: The macro generated output from MPRINT will also be written to external file C:\Users\Sarath
Annapareddy\Desktop\macroresol.sas while OPTIONS MPRINT and MFILE are set.

NOTE: There were 6 observations read from the data set WORK.DSN1.
NOTE: There were 6 observations read from the data set WORK.DSN2.
NOTE: There were 6 observations read from the data set WORK.DSN3.
NOTE: There were 6 observations read from the data set WORK.DSN4.
NOTE: The data set WORK.ALL has 24 observations and 1 variables.
NOTE: DATA statement used (Total process time):
real time 0.06 seconds
cpu time 0.06 seconds

macroresol.sas file.

data all;
set dsn1 dsn2 dsn3 dsn4 ;
run;


MACROGEN:

Option MACROGEN will turn on the macro expansion and is necessary when you use macros.


MPRINTNEST and MPRINTLOGIC:These options are available with SAS v9.0. These options can be useful when you use NESTED macros. You will see more information in the LOG file than what you usually see with MPRINT and MLOGIC options combine.

Both these options require the use of MPRINT and MLOGIC respectively.

Example code used here:

options macrogen mlogic mprint symbolgen mfile;
filename mprint 'C:\Users\Sarath Annapareddy\Desktop\macroresol.sas';

data dsn1;
input a @@;
cards;
1 2 3 5 6 7
;
run;

data dsn2;
input a @@;
cards;
4 5 6 9 8 6
;
run;

data dsn3;
input a @@ ;
cards;
21 22 23 24 25 26
;
run;

data dsn4;
input a @@;
cards;
10 11 12 13 14 15
;
run;

*Concatenating all the 4 datasets using a macro with the %DO LOOP;%macro concat;
data all;
set
%do i = 1 %to 4;
dsn&i
%end;
;
run;
%mend;

%concat;


  • LOG FILE:
Debugging Techniques:

Here are few techniques to debug a macro:

Check if %macro-%mend, %DO-%END and %IF-%THEN-%ELSE are used correctly in the code.
Check whether single or double quotes used for the macro variables.
Check for balancing of quotes.
Check whether you have used %LOCAL and or %GLOBAL in appropriate places.
Check the macro variable resolution using the %PUT statement whenever required.
Use SAS debugging options MACROGEN, MPRINT, MLOGIC and SYMBOLGEN
to make sure the macro code is executed as expected.


31 %macro concat;
32 data all;
33 set
34 %do i = 1 %to 4;
35 dsn&i
36 %end;
37 ; /* this additional ';' is necessary, the first ';' is for
38 the "%end", while the second ';' is for "set " */
39 run;
40 %mend;
41
42 %concat;

MLOGIC(CONCAT): Beginning execution.
MPRINT(CONCAT): data all;
NOTE: The macro generated output from MPRINT will also be written to external file C:\Users\Sarath
Annapareddy\Desktop\macoresol.sas while OPTIONS MPRINT and MFILE are set.
MLOGIC(CONCAT): %DO loop beginning; index variable I; start value is 1; stop value is 4; by value is
1.
SYMBOLGEN: Macro variable I resolves to 1
MLOGIC(CONCAT): %DO loop index variable I is now 2; loop will iterate again.
SYMBOLGEN: Macro variable I resolves to 2
MLOGIC(CONCAT): %DO loop index variable I is now 3; loop will iterate again.
SYMBOLGEN: Macro variable I resolves to 3
MLOGIC(CONCAT): %DO loop index variable I is now 4; loop will iterate again.
SYMBOLGEN: Macro variable I resolves to 4
MLOGIC(CONCAT): %DO loop index variable I is now 5; loop will not iterate again.
MPRINT(CONCAT): set dsn1 dsn2 dsn3 dsn4 ;
MPRINT(CONCAT): run;

NOTE: There were 6 observations read from the data set WORK.DSN1.
NOTE: There were 6 observations read from the data set WORK.DSN2.
NOTE: There were 6 observations read from the data set WORK.DSN3.
NOTE: There were 6 observations read from the data set WORK.DSN4.
NOTE: The data set WORK.ALL has 24 observations and 1 variables.
NOTE: DATA statement used (Total process time):
real time 0.06 seconds
cpu time 0.06 seconds


MLOGIC(CONCAT): Ending execution.

CALL SYMPUT vs CALL SYMPUTX

Call Symput:

Use CALL SYMPUT is you need to assign a data step value to a macro variable.

Syntax: Call Symput (“Macro variable”, character value)

The first argument to the Symput routine is the name of the macro variable to be assigned to the value from the second argument.

The second argument is the character value that will be assigned to the macro variable. The second argument need to be always a character value or if a numeric value is to be used it should convert first into character variable before assigning it to macro variable. It may lead to problems, if you don’t do the conversion from numeric to character. In this case, SAS automatically converts numeric value of the variable to character value before assigning it to macro variable and prints a message in the LOG saying that conversion happened.

See the example:

data _null_;
count=1978;
call symput('count',count);
run;
%put &count;

19 data _null_;
20 count=1978;
21 call symput('count',count);
22 run;

NOTE: Numeric values have been converted to character values at the places given by: (Line):(Column).
21:21
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.01 seconds


23 %put &count;
1978

Even though macro variable count is resolved to the value i.e 1978, SAS printed a note saying that NOTE: Numeric values have been converted to character values at the places given by: (Line):(Column). 21:21

To avoid that… you should do the conversion from numeric to character before assigning it to macro variable. Here is the syntax of that:

data _null_;
count=1978;
call symput('count',strip(put(count,8.)));
run;
%put &count;

29 data _null_;
30 count=1978;
31 call symput('count',left(put(count,8.)));
32 run;

NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds


33 %put &count;
1978

Note:

1) Even though we have created macro variable using the CALL SYMPUT but the same macro variable cannot be used in the same data step. The reason behind this is, macro code is compiled and executed before the data step code compiles and executes. So macro variable created by the CALL SYMPUT cannot available for the data step because macro variable compilation time occurs after or in the middle of the execution of the Data Step code.
(If a case arises where you have to access the same macro variable inside the data step, you can certainly do... by using two diff.. macro functions called RESOLVE or SYMGET)

2) SAS always aligns numeric values right and variable values get truncated as a part of this and to avoid that use the strip function to remove all the leading spaces as like in the above example.
3) If CALL SYMPUT is used outside the macro ( i.e open code) it creats global macro variable whereas it creats a local macro variable when it is used inside a macro.

CALL SYMPUTX:

SAS introduced CALL SYMPUTX in version 9 to address the pitfalls of CALL SYMPUT.

Advantages of CALL SYMPUTX over CALL SYMPUT include:

1) SYMPUTX automatically convert the numeric variables to character variables before assigning it to macro variable. (No need of manual conversion using PUT statement as given in the above example)

2) Call Symputx strips leading and trailing blanks. So no need of using STRIP or LEFT function to remove the leading spaces

Syntax: Call Symputx (“Macro Variable”, Character Value, Symbol Table)

First and second arguments are same as in CALL SYMPUT. The third argument (Symbol table) is optional and the valid value of it is G, L, and F. If we put G then the macro variable will be stored in the global symbol table, else if we specify L SAS will store the macro in the local symbol table, else if we don’t specify or specify F SAS follows the same rules as like for Call Symput.

Example:

data _null_;
count=1978;
call symputx('count',put(count,8.),’G’);
run;
%put &count;

29 data _null_;
30 count=1978;
31 call symputx('count',put(count,8.));
32 run;


NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds


33 %put &count;
1978

Note: If you use CALL SYMPUT instead of CALL SYMPUTX, the program executes in an identical manner, but a note is written to the SAS Log about conversion of numeric values to character values.


Here is the simple way to understand the diff between CALL SYMPUT AND CALL SYMPUTX:
Retrieved from: Using_the_SAS_V9_CALL_SYMPUTX_Routine from SAScommunity.org page:
Submitted by Michael A. Raithel.

The SAS V9 CALL SYMPUTX routine can save you keystrokes and lead to leaner, cleaner SAS programs.
Instead of using:
call symput('MACROVAR',trim(left(charvar)));

to load a SAS macro variable with a character string that might contain blanks, you could use SYMPUTX instead:
call symputX('MACROVAR',charvar);

Disclosure:

In the spirit of transparency and innovation, I want to share that some of the content on this blog is generated with the assistance of ChatGPT, an AI language model developed by OpenAI. While I use this tool to help brainstorm ideas and draft content, every post is carefully reviewed, edited, and personalized by me to ensure it aligns with my voice, values, and the needs of my readers. My goal is to provide you with accurate, valuable, and engaging content, and I believe that using AI as a creative aid helps achieve that. If you have any questions or feedback about this approach, feel free to reach out. Your trust and satisfaction are my top priorities.