Discover More Tips and Techniques on This Blog

Showing posts with label Macro. Show all posts
Showing posts with label Macro. Show all posts
Macro Debugging Options in SAS

Macro Debugging Options in SAS

The SAS Macro Facility is a powerful feature that allows for dynamic code generation and automation. However, when macros become complex, it can be challenging to understand how they are executing and where issues might arise. SAS provides several debugging options to help developers trace the execution of macros and diagnose problems. In this article, we will explore the following debugging options:

  • MPRINT
  • MLOGIC
  • SYMBOLGEN
  • MACROGEN
  • MFILE

MPRINT

The MPRINT option is used to display the SAS statements that are generated by macro execution. This option helps you see the actual code that a macro produces, which is essential for understanding what your macro is doing.

Basic Example:

options mprint;

%macro greet(name);
    %put Hello, &name!;
%mend greet;

%greet(Sarath);

When you run the above code with the MPRINT option enabled, you will see the following output in the SAS log:

MPRINT(GREET):   %put Hello, Sarath!;

This output shows that the macro successfully resolved the &name variable to "Sarath" and executed the %put statement with that value.

Advanced Example:

Consider a more complex macro that generates a data step based on input parameters:

options mprint;

%macro filter_data(age_limit);
    data filtered;
        set sashelp.class;
        where age > &age_limit;
    run;
%mend filter_data;

%filter_data(12);

With MPRINT enabled, the log will show the following:

MPRINT(FILTER_DATA):   data filtered;
MPRINT(FILTER_DATA):   set sashelp.class;
MPRINT(FILTER_DATA):   where age > 12;
MPRINT(FILTER_DATA):   run;

This output is the exact code generated and executed by the macro, making it easier to verify that your macro is working as intended.

MLOGIC

The MLOGIC option provides detailed information about the macro execution logic, including the evaluation of conditions, the flow of macro execution, and the resolution of macro variable values. This option is particularly useful when debugging complex macros that involve conditional logic and multiple macro variables.

Basic Example:

options mlogic;

%macro check_age(age);
    %if &age > 12 %then %put Age is greater than 12;
    %else %put Age is 12 or less;
%mend check_age;

%check_age(14);

The log output with MLOGIC enabled will be:

MLOGIC(CHECK_AGE):  Beginning execution.
MLOGIC(CHECK_AGE):  %IF condition &age > 12 is TRUE
MLOGIC(CHECK_AGE):  %PUT Age is greater than 12
Age is greater than 12
MLOGIC(CHECK_AGE):  Ending execution.

This output shows the logical flow within the macro, including how the %IF condition was evaluated and which branch of the logic was executed.

Advanced Example:

Let's consider a macro that processes a dataset differently based on a condition:

options mlogic;

%macro process_data(gender);
    %if &gender = M %then %do;
        data males;
            set sashelp.class;
            where sex = "M";
        run;
    %end;
    %else %do;
        data females;
            set sashelp.class;
            where sex = "F";
        run;
    %end;
%mend process_data;

%process_data(M);

With MLOGIC enabled, the log will detail how the macro made its decision:

MLOGIC(PROCESS_DATA):  Beginning execution.
MLOGIC(PROCESS_DATA):  %IF condition &gender = M is TRUE
MLOGIC(PROCESS_DATA):  %DO loop beginning.
MLOGIC(PROCESS_DATA):  %END loop.
MLOGIC(PROCESS_DATA):  Ending execution.

This output provides insight into the decision-making process within the macro, showing that the macro correctly identified the gender as "M" and executed the appropriate branch of code.

SYMBOLGEN

The SYMBOLGEN option is used to display the resolution of macro variables, showing their values before and after resolution. This option is crucial for understanding how macro variables are being substituted during macro execution.

Basic Example:

options symbolgen;

%let myvar = 20;

%macro show_var;
    %put The value of myvar is &myvar;
%mend show_var;

%show_var;

The log output with SYMBOLGEN enabled will show the resolution of the macro variable:

SYMBOLGEN:  Macro variable MYVAR resolves to 20
The value of myvar is 20

This output confirms that the macro variable &myvar was correctly resolved to "20" before being used in the %put statement.

Advanced Example:

Consider a macro that constructs a filename dynamically based on a date:

options symbolgen;

%let year = 2024;
%let month = 09;
%let day = 01;

%macro create_filename;
    %let filename = report_&year.&month.&day..txt;
    %put &filename;
%mend create_filename;

%create_filename;

The log output with SYMBOLGEN enabled will detail the resolution process:

SYMBOLGEN:  Macro variable YEAR resolves to 2024
SYMBOLGEN:  Macro variable MONTH resolves to 09
SYMBOLGEN:  Macro variable DAY resolves to 01
SYMBOLGEN:  Macro variable FILENAME resolves to report_20240901.txt
report_20240901.txt

This output shows how the macro variables were resolved and concatenated to form the final filename.

MACROGEN

The MACROGEN option displays the source code of macros during their compilation. This is useful when you need to verify the structure of your macros, especially when dealing with complex nested macros or dynamic macro generation.

Example:

options macrogen;

%macro example_macro;
    %put This is a simple macro;
%mend example_macro;

%example_macro;

With MACROGEN enabled, the log will show when the macro definition is complete:

MACROGEN(EXAMPLE_MACRO):  Macro definition is complete.
This is a simple macro

While this option is not as frequently used as the others, it can be helpful in ensuring that your macro definitions are compiled as expected, particularly in complex macro libraries.

MFILE

The MFILE option allows you to direct the output of the MPRINT option to an external file. This can be particularly useful when you want to save the generated code for documentation, further analysis, or debugging purposes.

Example:

In this example, we will save the generated code to a file named mprint_output.sas:

filename mprint_file 'C:\temp\mprint_output.sas';
options mfile mprint;

%macro example;
    data _null_;
        set sashelp.class;
        where age > 12;
        put 'Processing ' name= age=;
    run;
%mend example;

%example;

options nomfile;
filename mprint_file clear;

With this setup, the generated SAS code from the macro will be written to the specified file. You can then open this file in a text editor to review the code:

data _null_;
    set sashelp.class;
    where age > 12;
    put 'Processing ' name= age=;
run;

This option is extremely helpful when you need to review the generated code outside of the SAS environment or when the log becomes too cluttered.

Conclusion

Each of these macro debugging options provides valuable insights into the execution of SAS macros. By using MPRINT, MLOGIC, SYMBOLGEN, MACROGEN, and MFILE effectively, you can diagnose issues, understand the flow of your macros, and ensure that your code is executing as intended. Mastering these tools is an essential skill for any SAS programmer working with macros.

Macros are powerful tools in SAS programming, especially in SDTM (Study Data Tabulation Model) programming, where they can automate repetitive tasks and ensure consistency across datasets. However, debugging macros can be challenging due to their complexity and the way they handle data. This guide provides detailed strategies and examples for effectively debugging macros in SDTM programming.

1. Use the MPRINT Option to Trace Macro Execution

The MPRINT option in SAS helps trace the execution of macro code by printing the SAS statements generated by the macro to the log. This is especially useful when you want to see the resolved code that the macro generates.

Example: Consider a macro that generates an SDTM domain. By enabling MPRINT, you can see exactly what code is being executed, helping you identify where errors might occur.


options mprint;

%macro create_dm;
   data dm;
      set rawdata;
      usubjid = subject_id;
      age = input(age_raw, 8.);
      sex = gender;
      /* More variable mappings */
   run;
%mend create_dm;

%create_dm;

With MPRINT enabled, the log will show the actual data step code generated by the macro, making it easier to identify any issues.

2. Use the MLOGIC Option to Debug Macro Logic

The MLOGIC option prints information about the macro’s logic flow, including when macros are called, when macro variables are resolved, and the values they resolve to. This helps you understand the macro’s decision-making process.

Example: Use MLOGIC to trace how a macro variable is being resolved within a loop or conditional statement.


options mlogic;

%macro check_age;
   %let min_age = 18;
   %let max_age = 65;

   %if &min_age > &max_age %then %do;
      %put ERROR: Minimum age cannot be greater than maximum age.;
   %end;
   %else %do;
      data age_check;
         set rawdata;
         if age >= &min_age and age <= &max_age then valid_age = 1;
         else valid_age = 0;
      run;
   %end;
%mend check_age;

%check_age;

With MLOGIC enabled, the log will show how the macro variables min_age and max_age are being resolved and the flow of logic within the macro.

3. Use the SYMBOLGEN Option to Track Macro Variable Resolution

The SYMBOLGEN option prints the resolution of macro variables to the log. This is particularly useful for debugging issues related to macro variable values, especially when those variables are used in data steps or PROC SQL.

Example: If a macro is not producing the expected results, use SYMBOLGEN to check how each macro variable is being resolved.


options symbolgen;

%macro filter_by_sex(sex=);
   data filtered;
      set dm;
      where sex = "&sex.";
   run;
%mend filter_by_sex;

%filter_by_sex(sex=M);

The log will show how the sex variable is being resolved, helping you confirm that the correct value is being passed to the where statement.

4. Incorporate PUTLOG Statements for Custom Debugging

While MPRINT, MLOGIC, and SYMBOLGEN provide automatic logging, adding PUTLOG statements within your macros allows for custom debugging messages. This can be particularly helpful when you need to check specific conditions or values during macro execution.

Example: Use PUTLOG to debug a conditional macro that applies different transformations based on input parameters.


%macro transform_data(var=, method=);
   %if &method = log %then %do;
      data transformed;
         set rawdata;
         &var._log = log(&var.);
         putlog "NOTE: Log transformation applied to " &var=;
      run;
   %end;
   %else %if &method = sqrt %then %do;
      data transformed;
         set rawdata;
         &var._sqrt = sqrt(&var.);
         putlog "NOTE: Square root transformation applied to " &var=;
      run;
   %end;
   %else %do;
      %put ERROR: Invalid method specified. Use "log" or "sqrt".;
   %end;
%mend transform_data;

%transform_data(var=height, method=log);

The PUTLOG statement will output a note to the log indicating which transformation was applied, or an error message if an invalid method was specified.

5. Test Macros with Simple, Controlled Inputs

Before using a macro in a complex scenario, test it with simple, controlled inputs to ensure it behaves as expected. This helps isolate the macro's functionality and identify potential issues in a controlled environment.

Example: Test a macro that standardizes date formats with a small sample dataset to ensure it handles various date formats correctly.


data test_dates;
   input rawdate $10.;
   datalines;
2021-01-01
01JAN2021
2021/01/01
;
run;

%macro standardize_date(datevar=);
   data standardized;
      set test_dates;
      format &datevar yymmdd10.;
      &datevar = input(&datevar, anydtdte10.);
   run;

   proc print data=standardized;
   run;
%mend standardize_date;

%standardize_date(datevar=rawdate);

This example demonstrates testing a date standardization macro with a simple dataset to ensure it correctly processes different date formats.

6. Break Down Complex Macros into Smaller Components

Complex macros can be challenging to debug due to the multiple steps and logic involved. Breaking down a complex macro into smaller, more manageable components makes it easier to identify and fix issues.

Example: Instead of writing a single macro to process an entire SDTM domain, split it into smaller macros that handle specific tasks, such as variable mapping, data transformation, and output formatting.


%macro map_variables;
   data mapped;
      set rawdata;
      usubjid = subject_id;
      age = input(age_raw, 8.);
      sex = gender;
   run;
%mend map_variables;

%macro transform_data;
   data transformed;
      set mapped;
      if age < 18 then age_group = 'Child';
      else age_group = 'Adult';
   run;
%mend transform_data;

%macro output_data;
   proc print data=transformed;
   run;
%mend output_data;

%map_variables;
%transform_data;
%output_data;

This approach makes it easier to debug each step individually and ensures that each component works correctly before combining them into a larger process.

7. Use Macro Quoting Functions to Handle Special Characters

Special characters in macro variables can cause unexpected behavior. Macro quoting functions like %STR, %NRSTR, %QUOTE, and %NRQUOTE help handle these characters correctly.

Example: If a macro variable contains special characters like ampersands or percent signs, use macro quoting functions to prevent errors.


%let special_char_var = %str(50% discount);
%put &special_char_var;

%macro handle_special_chars(text=);
   %put NOTE: The text is: %quote(&text);
%mend handle_special_chars;

%handle_special_chars(text=Special &char handling);

The macro quoting functions ensure that special characters are handled correctly, preventing syntax errors or unexpected behavior.

8. Utilize the Debugger Macro

SAS provides a %DEBUGGER macro for debugging other macros. It allows you to step through a macro's execution and inspect variable values at each step.

Example: Use the %DEBUGGER macro to interactively debug a complex macro, inspecting variable values and execution flow in real-time.


%macro my_macro(var=);
   %local step1 step2;
   %let step1 = %eval(&var + 1);
   %let step2 = %eval(&step1 * 2);
   %put NOTE: Final value is &step2;
%mend my_macro;

/* Start the debugger */
%debugger my_macro(var=5);

The %DEBUGGER macro allows you to step through the execution of my_macro, inspect the values of step1 and step2, and identify any issues in the logic.

9. Generate Test Outputs for Verification

Generating intermediate outputs or log messages at key steps in your macro can help verify that each part of the macro is working correctly.

Example: Add steps to your macro that output temporary datasets or log specific values during execution, allowing you to verify that the macro is functioning as expected.


%macro process_data(var=);
   data step1;
      set rawdata;
      &var._step1 = &var. * 2;
   run;
   proc print data=step1;
   run;

   data step2;
      set step1;
      &var._step2 = &var._step1 + 10;
   run;
   proc print data=step2;
   run;
%mend process_data;

%process_data(var=age);

In this example, intermediate datasets step1 and step2 are printed, allowing you to verify the transformations applied to the age variable at each stage.

10. Maintain a Debugging Log for Complex Macros

For complex macros, maintain a debugging log where you document the issues encountered, the steps taken to resolve them, and any notes on how the macro behaves under different conditions. This log can be invaluable for future debugging efforts.

Example: Create a debugging log as you develop and test a macro, noting any issues with specific data inputs, unexpected behaviors, or areas of the code that required special handling.


/* Debugging Log for %process_data Macro
   - Issue: The macro fails when var contains missing values
   - Resolution: Added a check for missing values before processing
   - Note: The macro works correctly with both positive and negative values
   - Date: YYYY-MM-DD
   - Author: Your Name
*/
%macro process_data(var=);
   %if &var = . %then %do;
      %put ERROR: Missing value for &var.. Macro will not execute.;
      %return;
   %end;

   data processed;
      set rawdata;
      &var._processed = &var. * 2;
   run;
%mend process_data;

%process_data(var=age);

This debugging log helps keep track of the macro's development and any issues resolved along the way, providing a valuable resource for future maintenance or enhancements.

Conclusion

Macro debugging in SDTM programming can be challenging, but by using these techniques—such as enabling logging options, breaking down complex macros, using custom PUTLOG statements, and maintaining a debugging log—you can effectively troubleshoot and resolve issues in your macros. These practices not only help ensure that your macros run correctly but also enhance the overall quality and reliability of your SDTM programming.

How to create a macro variable containing a list of variables in a DATA set

Sometimes it is very handy to have a macro variable contanining the variables names of the dataset. Here are the 2 different ways you can create a macro variable with list of variables names ...

*Method1: Using Proc Contents and Proc SQL;



proc contents data=sashelp.class out=class;
run;

proc sql noprint;
select distinct(name) into:vars separated by " " from class;
quit;


%put &vars;


*Method2: Using SASHELP tables and Proc SQL;


data class;
set sashelp.vcolumn(where=(libname="SASHELP" and memname="CLASS"));
keep name;
run;


proc sql noprint;
select distinct(name) into:vars separated by " " from class;
quit;

%put &vars;

maxvarlen_macro: Check the Length of all character variables length is LT 200

MAXVARLEN Macro:
According to FDA released the Guidance for Industry: Providing Regulatory
Submission in Electronic Format – NDAs which was released in Jan 1999, one of the important point to comply with the agency’s regulations is : The length of any character values cannot be more than 200 characters.

Here is the macro which will give us the list of character variables whose actual length (not the assigned) is greater than 200. You can use this program to check the maximum length of all variables of any dataset at once. This macro will create a table with list of variables and their length.
***********************************************************************;
*** Program: macro_maxvarlen.sas ***;
*** Version: 1.0 ***;
*** Client: ***;
*** Protocol: ***;
*** Programmer: sarath Annapareddy ***;
*** Date: 22APR2009 ***;
*** Purpose: Macro used to check the list of variables whose ***;
*** length is GT 200. ***;
*** ***;
******************************************************************* ***;
libname prodn 'H:\Company\Client\Testing\XXXX\XXXXX\Test map datasets';

option nofmterr;

%macro maxvarlen(base,dsn);data dsn;
set sashelp.vcolumn(where=(libname=upcase("&base") and memname=upcase("&dsn") and type='char'));
call symput(cats("var",_n_),name);
id=_n_;
keep name id;
run;

*Counting number of character variables in the dataset;
proc sql noprint;
select count(*)into :nvars from dsn;
quit;

*Computing max. length of each character variable in the dataset;
%do i = 1 %to &nvars;
proc sql noprint;
create table maxlen&i as
select max(length(&&var&i)) as mlen from &base..&dsn
quit;
%end;

*Concatenating all the datasets;
data final;
id=_n_;
set %do i= 1 %to &nvars;
maxlen&i
%end;
;
run;

%mend;
%maxvarlen
(prodn,ae);

*Final dataset with list of variables whose length is GT 200;proc sql;
create table mxvarlen as
select a.name ,b.mlen
from dsn as a, final as b
where a.id=b.id and mlen gt 200;
quit;

How to check if the File is exist or not in SAS

How to check if the File is exist or not in SAS:

Guys… Let me try explaining how to check if the file exist in the library or directory using SAS.

Here I am writing a macro to check if the file exist in the directory or not.

Here is the way to check it…

%macro check(dir= ) ;
%if %sysfunc(fileexist(&dir)) %then %do;
%put File Exists ;
%end;


%else %do ;
%put File doesn’t exist.;
%end ;

%mend ;
%check(dir="C:\Documents and Settings\sannapareddy\Desktop\Holidays 2009.docx");

%sysfunc option empowers me to use the same Data step functions outside the Data step. Almost all of the Data step functions are available to use outside the data step if we use %sysfunc.

fileexist option, verifies the existence of an external file. It can also verifies the SAS library.


Here is another simple technique to check.....

data _null_;
x=filexist('C:\Documents and Settings\sannapareddy\Desktop\Holidays 2009.docx');
call symput('myvar1',x);
run;


%put &myvar1;

Call symput is used to create a macro variable( myvar1)with the variable 'X' value assigned to it.

See the log for details,.... if the value you see in log is one ... then the file exists, if the value in the log is 0 the the file doesn't.


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.