I am creating a macro, and would like to validate a parameter, i.e. to check if a list of values is contained in another list of values. If this is NOT the case, I will put an error message to the user.
The code I was trying:
%macro ValidateCountries(country, countrylist) /minoperator mindelimiter=' ';
%if %upcase(&country.) in (USA UK ENG) and %upcase(&countrylist.) in (USA UK ENG) %then %do;
%local answer;
%if &country. in &countrylist. %then %do;
%let answer= 1;
%end;
%else %do;
%let answer= 0;
%end;
&answer;
%end;
%else %do;
%put Error: country should be one of: USA UK ENG.
countrylist may only contain some of USA UK ENG. ;
%end;
%mend;
I believe the problem is in this code:
and %upcase(&countrylist.) in (USA UK ENG) %then %do;
Thanks for the help.
When you are done compare to this:
%macro ValidateCountries(country, countrylist) /minoperator mindelimiter=' ';
%local answer i next list;
%let list=%qupcase(USA UK ENG);
%let answer=1;
%if not (%qupcase(&country) in &list) %then %do;
%let answer=0;
%put ERROR: COUNTRY value "&country" is not in &=list;
%end;
%do i=1 %to %sysfunc(countw(&countrylist));
%let next=%qscan(&countrylist,&i,%str( ));
%if not (%qupcase(&next) in &list) %then %do;
%let answer=0;
%put ERROR: COUNTRYLIST value "&next" is not in &=list;
%end;
%end;
&answer
%mend;
Results:
283 %put %ValidateCountries(uk,usa uk); 1 284 %put %validateCountries(usa uk ,france usa uk); ERROR: COUNTRY value "usa uk" is not in LIST=USA UK ENG ERROR: COUNTRYLIST value "france" is not in LIST=USA UK ENG 0
@SasStatistics wrote:
I believe the problem is in this code:
and %upcase(&countrylist.) in (USA UK ENG) %then %do;
Thanks for the help.
It's not clear what the purpose of this part of the code is. But it is not a syntax error.
Thanks @PaigeMiller . I hope this example makes it more clear:
%let MyRes1 = %ValidateCountries(USA, USA UK); * Program goes to the %else %do statement, but USA and UK is in the list of USA, UK and ENG so I would like it to return the answer 1. ;
%macro ValidateCountries(country, countrylist) /minoperator mindelimiter=' ';
%if %upcase(&country.) in (&countrylist) %then 1;
%else 0;
%mend;
%put ANSWER %validateCountries(uk,USA UK ENG);
%put ANSWER2 %validateCountries(turkey,USA UK ENG);
Would this work for you?
@SasStatistics wrote:
Unfortunately not, I must beforehand validate that countrylist is a list only containing the combinations of (USA, UK, ENG). For example (USA and UK) would be valid as would USA alone.
But USA, UK, GER would not be valid and should return an error.
Why then don't you just hardcode the country list instead of making a variable that could have values you don't want?
%macro ValidateCountries(country) /minoperator mindelimiter=' ';
%if %upcase(&country.) in (USA UK ENG) %then 1;
%else 0;
%mend;
%put ANSWER %validateCountries(uk);
%put ANSWER2 %validateCountries(turkey);
Going back to your original code which has this:
%if %upcase(&country.) in (USA UK ENG) and %upcase(&countrylist.) in (USA UK ENG) %then %do;
You need to check &countrylist is valid in one %IF block, and check if the &Country is contained in &countrylist in a different %IF block.
To check if &countrylist is valid, you would need to specifically loop through each element of &countrylist.
@SasStatistics wrote:
Problem is, both if conditions must fulfilled at the same time. This logic only looks at one at the time?
Sequential testing of each condition gets you to the same end result. If the countrylist is wrong, you get notified. If the country is not in the countrylist, you get notified.
Are you just trying to check if ONE value is in a list of possible values? Or are you trying to check if all of a list of values in in another list?
Set the result to GOOD and then loop over the list of words to check and set it BAD for any failure.
Example:
%macro ValidateCountries(country, countrylist) /minoperator mindelimiter=' ';
%local answer i next;
%let answer=1;
%do i=1 %to %sysfunc(countw(&country));
%let next=%qscan(&country,&i,%str( ));
%if not (%qupcase(&next) in %qupcase(&countrylist)) %then %do;
%let answer=0;
%put ERROR: Value &next is not in list: &countrylist;
%end;
%end;
%if not &answer %then %put ERROR: Invalid list of countries: &=country;
&answer
%mend;
%put %ValidateCountries(uk,usa uk);
%put %validateCountries(usa uk france,usa uk);
The purpose of the validation code:
%if %upcase(&country.) in (USA UK ENG) and %upcase(&countrylist.) in (USA UK ENG) %then %do;
is to:
1. &country may only be ONE of the value USA, UK, ENG. For example: country = USA UK is invalid since it is two values, it may only be one. Country = USA is valid. Country = GER is invalid.
2. Countrylist is a "list" and may only contain USA, UK, ENG. For example: countrylist = USA UK is valid. Countrylist = USA UK ENG is valid. Countrylist = USA GER is invalid. Countrylist = USA USA UK is valid although it is bad programming (or perhaps a misstake).
Thanks @Tom and hope it is clear.
So modify my version to do what you want.
If you have trouble post your code so we can see how to help you.
My try which I know is wrong, but I have trouble implementing the check for two conditions when one of the condition involves looping.
/*Validation 1: &country may only be ONE of the value USA, UK, ENG.*/
/*Validation 2: Countrylist is a "list" and may only contain USA, UK, ENG. For example: countrylist = USA UK is valid.
Countrylist = USA UK ENG is valid. Countrylist = USA GER is invalid.
Countrylist = USA USA UK is valid although it is bad programming (or perhaps a misstake).*/
/* These two validation conditions must both be fullfilled at the same time*/
%macro ValidateCountries(country, countrylist) /minoperator mindelimiter=' ';
%if %upcase(&country.) in (USA UK ENG)
AND /* Have trouble how to check that all the looping cases are true in an AND statement? */
%do i=1 %to %sysfunc(countw(&countrylist.));
%let next=%qscan(&countrylist.,&i,%str( ));
%if (%qupcase(&next) in %qupcase(&countrylist)) %then %do;
%end;
%then %do;
%local answer;
%if &country. in &countrylist. %then %do;
%let answer= 1;
%end;
%else %do;
%let answer= 0;
%end;
&answer;
%end;
%else %do;
%put Error: country should be one of: USA UK ENG.
countrylist may only contain some of USA UK ENG. ;
%end;
%mend;
When you are done compare to this:
%macro ValidateCountries(country, countrylist) /minoperator mindelimiter=' ';
%local answer i next list;
%let list=%qupcase(USA UK ENG);
%let answer=1;
%if not (%qupcase(&country) in &list) %then %do;
%let answer=0;
%put ERROR: COUNTRY value "&country" is not in &=list;
%end;
%do i=1 %to %sysfunc(countw(&countrylist));
%let next=%qscan(&countrylist,&i,%str( ));
%if not (%qupcase(&next) in &list) %then %do;
%let answer=0;
%put ERROR: COUNTRYLIST value "&next" is not in &=list;
%end;
%end;
&answer
%mend;
Results:
283 %put %ValidateCountries(uk,usa uk); 1 284 %put %validateCountries(usa uk ,france usa uk); ERROR: COUNTRY value "usa uk" is not in LIST=USA UK ENG ERROR: COUNTRYLIST value "france" is not in LIST=USA UK ENG 0
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.