BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
saspert
Pyrite | Level 9

Hi,

I have using sas macro to check the current system time and do calculations based on it. However, I am getting an error. Can someone point out if I have incorrect data usage?

%global timeflag tc;
%macro _timecheck;
data _null_;
call symput ('tc',strip(minute(time())));
run;
%put "&tc is the system time" ;
%if 0<= &tc <= 29 %then
%do;
%let timeflag = A ;
%put "the flag is set to &timeflag";
%end;
%else %if 30<= &tc <= 59 %then %do;
%let timeflag = B;
%put "the flag is set to &timeflag";
%end;
%mend _timecheck;
%_timecheck


           (CATS('PBG',LEFT(put(t2.&prcname.Plant,11.),2), SUBSTR(t2.&prcname.Line,1,1))) LABEL="&prcname. Unit" AS
            &prcname.Unit,
          /* _30mintime */
            (PUT(round(t2.&prcname.Time,hms(0,30,00)), DATETIME.)) LABEL="&prcname._30mintime" AS &prcname._30mintime,
          /* _1hrtime */
            (PUT(round(intnx('hour',t2.&prcname.Time,-1 )), DATETIME.) ) LABEL="&prcname._1hrtime" AS &prcname._1hrtime,
          /* _daytime */
            (put(datepart(t2.&prcname.Time), MMDDYY10.)) LABEL="&prcname._daytime" AS &prcname._daytime,
          /* _CustomHrBin */
            (CASE
            WHEN ( &timeflag = A) and ( 0<= (minute(t2.&prcname.Time)) <= 29 )  THEN
            PUT(round(t2.&prcname.Time,hms(1,0,00)), DATETIME.)
            WHEN (  &timeflag = A) and ( 30<= (minute(t2.&prcname.Time)) <= 59 )  then PUT(intnx('hour'
            ,round(t2.&prcname.Time,hms(1,0,00)),-1), DATETIME.)
            when (  &timeflag = B) and ( 0<= (minute(t2.&prcname.Time)) <= 29 ) then PUT(intnx('minutes',
            round(t2.&prcname.Time,hms(1,0,00)), -30),DATETIME.)
            when   (  &timeflag = B)  and  ( 30<= (minute(t2.&prcname.Time)) <= 59 ) then PUT(intnx('minute'
            ,round(t2.&prcname.Time,hms(1,0,00)),-30),DATETIME.)
            END
           
            )  AS _&prcname._CustomHrBin


SYMBOLGEN:  Macro variable PRCNAME resolves to FinalSim
"the currenct process being executed is FinalSim"
SYMBOLGEN:  Macro variable PRCNAME resolves to FinalSim
SYMBOLGEN:  Macro variable TIMEFLAG resolves to A

WARNING: Function LEFT requires at most 1 argument(s). The extra one(s) will be ignored.
NOTE: A CASE expression has no ELSE clause. Cases not accounted for by the WHEN clauses will result in a missing value for the CASE
      expression.
ERROR: The following columns were not found in the contributing tables: A, B.
NOTE: PROC SQL set option NOEXEC and will continue to check the syntax of statements.
MPRINT(_BUILD_METRICS):   QUIT;
NOTE: The SAS System stopped processing this step because of errors.
NOTE: PROCEDURE SQL used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds

The case statement above worked before substituting the macro variable.

Thanks,

Raj.

1 ACCEPTED SOLUTION

Accepted Solutions
Reeza
Super User

I don't know what the error in your code is, but I believe the following code doesn't work in macro language:

%if 0<= &tc <= 29 %then

It should be

%if 0<= &tc  and &tc <= 29 %then

View solution in original post

13 REPLIES 13
Reeza
Super User

I don't know what the error in your code is, but I believe the following code doesn't work in macro language:

%if 0<= &tc <= 29 %then

It should be

%if 0<= &tc  and &tc <= 29 %then

Vince28_Statcan
Quartz | Level 8

I can't tell much for the entire program, but the error listed above from your log comes from the fact that

WHEN ( &timeflag = A)

when (  &timeflag = B)

are not quoted, that is, SQL attempts to resolve if  variable B = variable B and not if "B" = "B". So the first step to see if there are anymore errors would be to replace the when lines by the following

WHEN ( "&timeflag"="A")

Make sure you use double quotes as single quotes will prevent the macro variable &timeflag to resolve to A and thus will always lead to a binary value FALSE since the string '&timeflag' is not equal to the string 'A'

saspert
Pyrite | Level 9


Hi Vince,

I think I am still tripping up with getting the right syntax for checking macros. I have attached the code and log. I am trying to check if the macro variables i and j have values then create the ALLDATA dataset. For all other values of i and j, merge (not append) the data from &&pcode&i.._LINE_DELTA_&&metric&j.. into the ALLDATA dataset.

%if  (%eval("&j ") = "1" AND %eval("&i" ) ="1" )  %then
  %do;
  DATA ALLDATA;
  set &&pcode&i.._LINE_DELTA_&&metric&j..;
  run;
  %end ;
%else %if ( %eval("&j" ) <> "1" OR  %eval("&j" ) <>"1" ) %then
  %do;
  PROC SQL;
  create table ALLDATA
  as (select * from &&pcode&i.._LINE_DELTA_&&metric&j.. t1
  right  join CUSTOMHRBIN_VALUES t2
   on (t1._&&pcode&i.._CustomHrBinA=t2._customhrbin
   or t1._&&pcode&i.._CustomHrBinB=t2._customhrbin)
  union select * from WORK.ALLDATA
   )
   ;
  quit;
  %end;


SYMBOLGEN:  Macro variable J resolves to 1
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:
       "1 "
SYMBOLGEN:  Macro variable I resolves to 3
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:
       "3"
MLOGIC(_LOOP_FOR_SELECTED_PROCESSES._PROCESS_LEGS._METRICS):  %IF condition (%eval("&j ") = "1" AND %eval("&i" ) ="1" ) is FALSE
ERROR: The macro _METRICS will stop executing.
MLOGIC(_LOOP_FOR_SELECTED_PROCESSES._PROCESS_LEGS._METRICS):  Ending execution.
MLOGIC(_LOOP_FOR_SELECTED_PROCESSES._PROCESS_LEGS):  %DO loop index variable J is now 2; loop will iterate again.
60                                                         The SAS System                              09:06 Thursday, July 25, 2013

MPRINT(_PROCESS_LEGS):   *loop through individual metric;
MLOGIC(_LOOP_FOR_SELECTED_PROCESSES._PROCESS_LEGS._METRICS):  Beginning execution.
SYMBOLGEN:  && resolves to &.
SYMBOLGEN:  Macro variable J resolves to 2
SYMBOLGEN:  Macro variable METRIC2 resolves to Voc

















Tom
Super User Tom
Super User

%EVAL() is for evaluating integer arithmetic (or boolean logic).  Have quotes inside of %EVAL() is going to cause errors.

Try just submitting the code:  %put %eval("1") ;  And read the generated error message.

Perhaps you are confusing %eval() with the normal macro variable processing of replacing &VARNAME with the value of the macro variable VARNAME?  If it helps I normally consider that as macro variable EXPANSION (rather than evaluation).

Most likely you want to replace

%if  (%eval("&j ") = "1" AND %eval("&i" ) ="1" )  %then %do;

With

%if  ("&j" = "1" AND "&i" ="1" )  %then %do;

saspert
Pyrite | Level 9

Many thanks Tom.

Vince28_Statcan
Quartz | Level 8

Hi Saspert,

The first 2 errors you get are fairly simple. Macro variables don't distinguish character from numeric. Everything is, a priori, considered text. When you use %eval, it simply expects the text string to be all numeric characters or arithmetic operators.

Thus, when you attempt to %eval("&j"), as the "" are not numeric characters or operators, you receive the error you are seeing. The proper way to do this syntax is "%eval(&j)"="1". There, the eval function will attempt to evaluate 1 and not "1". However, %eval should only be necessary if an arithmetic or logical operation needs to be resolved. You don't need to %eval(&j). Simply

%if ("&j"="1" and "&i"="1") %then ...

should achieve your desired results. I believe correcting this will solve the mlogic errors as well so try this and if there is still errors, I should reply somewhat fast. I have a very long program running and am quite bored self-learning in the mean time. For the sake of understanding, you can try both using the corrected "%eval()" and without the eval and see the difference it does in the log via mlogic

Vincent

saspert
Pyrite | Level 9

Many thanks Vince28. I think copying the exact syntax seems to work. Even " &j " or "&j." will not work.

saspert
Pyrite | Level 9

Hi guys,

Additional question. So the first %if condition seems to be working fine but the %else %if conditions dont seem to be working.

SYMBOLGEN:  Macro variable J resolves to 2

SYMBOLGEN:  Macro variable I resolves to 2

MLOGIC(_CONTROL_LOOP._PROCESS_LEGS._METRICS):  %IF condition ("&j" = "1" AND "&i" ="1" ) is FALSE

SYMBOLGEN:  Macro variable I resolves to 2

SYMBOLGEN:  Macro variable J resolves to 2

ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:

       ( "&i"  = "1" and  "&j" <> "1" )

ERROR: The macro _METRICS will stop executing.

Am i missing anything?

Thanks,

saspert








saspert
Pyrite | Level 9

Got the answer. macro logic does not like <>. When I used NE it worked.

Tom
Super User Tom
Super User

Not sure you wanted to use the MAX operator even if macro language supported it.

345  data _null_;

346    a='1';

347    b='2';

348    c= a <> b;

NOTE: The "<>" operator is interpreted as "MAX".

349    put c= ;

350  run;

c=2


Tom
Super User Tom
Super User

The use of multiple comparison operators does NOT work the same in macro language as it does in normal SAS code.  Instead of evaluating (A < B < C) as the same as (A < B and B < C) it first converts (A < B) to 0 or 1 based on whether it is true or false and then compares the result to C.  Try these two :

%put %eval( 0 < 4 < 1 ) ;

%put %eval( 0 < 4 <= 1 ) ;

But since you are already calling a data step you can just eliminate using macro logic and use normal data step logic instead. 

You can also use SYMPUTX to eliminate the need to convert numbers to character strings or the need for a %GLOBAL statement.

%macro _timecheck;

  data _null_;

     tc = minute(time());

     if 0 <= tc <= 29 then timeflag='A';

     else timeflag='B';

     call symputx('tc',tc,'G');

     call symputx('timeflag',timeflag,'G');

  run;

%mend _timecheck;

%_timecheck ;

%put timeflag=&timeflag tc=&tc ;

saspert
Pyrite | Level 9

Thanks eveyone. I have a question related to sas nested macros. I have two processes that I need to run the outer macro for and two metrics that I need to run the inner macro loop for. Originally I had the macro logic like this. Is that correct?

Data MESTGT.include_processes;
length pname $20.;
input pname;
cards;
FinalSim
AcidEtch
run;

Data MESTGT.include_metrics;
length metricname $20.;
input metricname;
cards;
Total_eff
Voc
;
run;


Data _null_;
set MESTGT.include_processes;
call symput ('pcode'||strip(_n_),strip(pname));
call symput ('nproc', strip(_n_));
run;

Data _null_;
set MESTGT.include_metrics;
call symput ('metric'||strip(_n_),strip(metricname));
call symput ('nmetric', strip(_n_));
run;


%macro _process_legs (pcode=);

....
    %macro _metrics
    %mend _metrics;

    /**Loop Through each individual metric for a single process leg**/

   %do j= 1 %to &nmetric; *loop through individual metric;
   %_metrics(metric=&&metric&j..)


%end;


%mend _process_legs;

/**Control Loop**/
%macro _loop_for_selected_processes;
%let i= ;
/****loops through individual leg/process***/
%do i = 1 %to &nproc;
%let j=;
%_process_legs(pcode=&&pcode&i..)
%end;

%mend _loop_for_selected_processes;
%_loop_for_selected_processes

Tom
Super User Tom
Super User

Also I am not sure what that fragment of SQL code is trying to do, but this part of it makes me worried.

   ( &timeflag = A)

If the values of the macro variable TIMEFLAG is either A or B then this will result in one of two possible code fragments:

( A = A)

( B = A)

So you are comparing the values of two data set variables.

The first will always be true (at least in SAS code, in other flavors of SQL if A is null then this might be false).

The second could be true if the value of B happens to equal the value of A.

If that is NOT what you wanted the perhaps you meant to code the test as:

   ( "&timeflag" = "A")

So that SAS is comparing two literal strings instead of referencing variables.

sas-innovate-2024.png

Today is the last day to save with the early bird rate! Register today for just $695 - $100 off the standard rate.

 

Plus, pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 13 replies
  • 2655 views
  • 7 likes
  • 4 in conversation