PRXMATCH in SAS EG don't work in open code - sas

I have this little code in SAS EG open code, it gives me 0 in A and I don't understand why!!!
%let ph=FONDS DE BOURSE;
%LET A=%sysfunc(PRXMATCH("/bourse/i","&ph"));
%put &A;
The result :
%let ph=FONDS DE BOURSE;
%LET A=%sysfunc(PRXMATCH("/bourse/i","&ph"));
SYMBOLGEN: La macro-variable PH est résolue en FONDS DE BOURSE
%put &A;
SYMBOLGEN: La macro-variable A est résolue en 0
0
Please, can you help ?
Thank you!

When using macros, you do not need to use quotation marks for string arguments in functions. Quotation marks are passed exactly as-is to PRXMATCH since the SAS macro facility is designed to process raw text. Remove your quotation marks and it will work as expected.
%let ph=FONDS DE BOURSE;
%LET A=%sysfunc(PRXMATCH(/bourse/i,&ph));
%put &A;
When using a data step, you will need to use quotation marks for the first part of the argument. Unquoted strings are processed as variables.
data test;
ph='FONDS DE BOURSE';
A=PRXMATCH("/bourse/i", ph);
run;

Related

SAS MACRO - concrenate SQL strings in macro

I have a libY.tableX that have for each record some SQL strings like the ones below and other fields to write the result of their execution.
select count(*) from libZ.tableK
select sum(fieldV) from libZ.tableK
select min(dsitact) from libZ.tableK
This my steps:
the user is prompted to select a lib and table and the value is passed to the vars &sel_livraria and &sel_tabela;
My 1st block is a proc sql to get all the sql string from that record.
My 2nd block is trying to concrenate all that strings to use further on to update my table with the results. The macro %isBlank is the one recommended by Chang CHung and John King in their sas papper;
My 3th block is to execute that concrenated sql string and update the table with results.
%macro exec_strings;
proc sql noprint ;
select livraria, tabela, sql_tot_linhas, sql_sum_num, sql_min_data, sql_max_data
into :livraria, :tabela, :sql_tot_linhas, :sql_sum_num, :sql_min_data, :sql_max_data
from libY.tableX
where livraria='&sel_livraria'
and tabela='&sel_tabela';
quit;
%LET mystring1 =%str(tot_linhas=(&sql_tot_linhas));
%LET separador =%str(,);
%if %isBlank(&sql_sum_num) %then %LET mystring2=&mystring1;
%else %LET mystring2= %sysfunc(catx(&separador,&mystring1,%str(sum_num=(&sql_tot_linhas))));
%if %isBlank(&sql_min_data) %then %LET mystring3=&mystring2 ;
%else %LET mystring3= %sysfunc(catx(&separador,&mystring2,%str(min_data=(&sql_min_data))));
%if %isBlank(&sql_max_data) %then %LET mystring0=&mystring3;
%else %LET mystring0= %sysfunc(catx(&separador,&mystring3,%str(max_data=(&sql_min_data))));
%PUT &mystring0;
proc sql noprint;
update libY.tableX
set &mystring0
where livraria='&sel_livraria'
and tabela='&sel_tabela';
quit;
%mend;
My problem with the code above is that iam getting this error in my final concrenated string, &mystring0.
tot_linhas=(&sql_tot_linhas),sum_num=(&sql_tot_linhas),min_data=(&sql_min_data),max_data=(&sql_min_data)
_ _ _ _
ERROR 22-322: Syntax error, expecting one of the following: a name, a quoted string, a numeric constant, a datetime constant, a missing value, BTRIM, INPUT, PUT, SUBSTRING, USER.
Any help appreciated
Ok, so i follow Tom comments and ended with a proc sql solution that works!
proc sql;
select sql_tot_linhas,
(case when sql_sum_num = '' then "0" else sql_sum_num end),
(case when sql_min_data = '' then "." else sql_min_data end),
(case when sql_max_data = '' then "." else sql_max_data end)
into:sql_linhas, :sql_numeros, :sql_mindata, :sql_mxdata
from libY.tableX
where livraria="&sel_livraria"
and tabela="&sel_tabela";
quit;
proc sql;
update libY.tableX
set tot_linhas = (&sql_linhas),
sum_num =(&sql_numeros),
min_data = (&sql_mindata),
max_data = (&sql_mxdata)
where livraria="&sel_livraria"
and tabela="&sel_tabela";
quit;
Tks Tom :)
It is very hard to tell from your description what it is you are trying to do, but there are some clear coding issues in the snippets of code you did share.
First is that macro expressions are not evaluated in string literals bounded by single quotes. You must use double quotes.
where livraria="&sel_livraria"
Second is you do not want to use any of the CAT...() SAS functions in macro code. Mainly because you don't need them. If you want to concatenate values in macro code just type them next to each other. But also because they do not work well with %SYSFUNC() because they allow their arguments to be either numeric or character so %SYSFUNC() will have to guess from the strings you pass it whether it should tell the SAS function those strings are numeric or character values.
So perhaps something like:
%let mystring=tot_linhas=(&sql_tot_linhas);
%if not %isBlank(&sql_sum_num) %then
%LET mystring=&mystring,sum_num=(&sql_tot_linhas)
;
%if not %isBlank(&sql_min_data) %then
%LET mystring=&mystring,min_data=(&sql_min_data)
;
%if not %isBlank(&sql_max_data) %then
%LET mystring=&mystring,max_data=(&sql_max_data)
;
Note that I also cleaned up some obvious errors when modifying that code. Like the extra & in the value passed to the %ISBLANK() macro and the assignment of the min value to the max variable.
But it would probably be easier to generate the strings in a data step where you can test the values of the actual variables and if needed actually use the CATX() function.

SAS accessing the macro variable name

I have some macro variables and each is assigned with a value. How can I get the name of the variables from their value?
For example I have assigned each person an age value. &Amy=12, &Peter=10.
I also have a macro function calculating something else, say weight.
%macro weight(name=);
%let weight=&name*10;
%put &name.'s weight is &weight.;
%mend;
if I run %weight(name=Amy) I want to get the result as "Amy's weight is 120".
how can i get the result as "Amy" instead of "12"?
Thanks
Nicely evil! That little single quote in the "Amy's" messes things up quite a bit. SAS seems to get confused about trying to evaluate the rest of the macro as a quoted string.
Start with the "magic string" to end all quotes, and make sure you've enabled macro output.
Once you do that, the following should work. Note the additional ampersands before name, as another responder suggested.
;*';*";*/;quit;
options mprint;
%let Amy = 12;
%macro weightmacro(name=);
%let weight=%sysevalf(&&&name..*10);
%put &name.s weight is &weight.;
%mend;
%weightmacro(name=Amy);
This will get you part of the way there. Note that having the apostrophe there is slightly problematic, you'll need to escape that or quote it out. I've ignored that for now. For the rest of your question:
Add more & to resolve a macro variable that's nested
Use %SYSEVALF() to do calculations with macro variables
%let Amy = 12;
%macro weight(name=);
%let weight=%sysevalf(&&&name*10);
%put &name. weight is &weight.;
%mend;
%weight(name=Amy);
If the point is the possessive noun that can be accomplished with %str(%');
357 %let Amy = 12;
358 %macro weightmacro(name=);
359 %let weight=%sysevalf(&&&name..*10);
360 %put &name.%str(%'s) weight is &weight.;
361 %mend;
362 %weightmacro(name=Amy);
Amy's weight is 120

How to mask "OR" with variable list passed through using SYSPBUFF in macro

I'm using SYSPBUFF to pass through various numbers of parameters into a macro. Specifically, I am passing through a list of states. One of the states being used is Oregon or "OR" and that one state is causing me error.
I get the error "ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: &ST^=
ERROR: The condition in the %DO %WHILE loop, &ST^=, yielded an invalid or missing value, . The macro will stop executing.
I've used all the various quoting masks to try to resolve this issue but none of it is working.
&STATES includes the following states:
AK,AZ,CA,HI,ID,NV,OR,WA
Here is my current code:
RSUBMIT;
PROC SQL;
connect to oracle
(path=DW user=&USER pw=&PW);
%macro DTCNT() / parmbuff;
%let i=1;
%let ST=%scan(&SYSPBUFF,&I);
%do %while (&ST^=);
CREATE TABLE MD_&ST._IP_ADJDT_CNTS_S1 AS
select *
from connection to oracle
(SELECT adjudication_date,
count (*) as LINE_CNT
from MD_r&NUM..&ST._IP_hdr_f
group by adjudication_date
order by adjudication_date);
%let i=%eval(&I+1);
%let ST=%scan(&SYSPBUFF,&I);
%end;
%mend DTCNT;
%DTCNT(&STATES);
disconnect from oracle;
QUIT;
ENDRSUBMIT;
Any assistance would be greatly appreciated.
Thanks in advance.
The issue here is Oregon. Its abbreviation is OR, which is also a reserved word (oops!). Remember the macro language is just text that is then parsed like normal - so when it finds &ST and translates to OR, it sees that as
%do %while (or ^= )
which causes it to get confused since it doesn't see anything to use with or.
You can use macro quoting here to cause SAS not to treat it like the boolean operator. %SUPERQ is the goto one for me, but a few of them should work.
Here's an example. I added some extra stuff to scan also to handle the parens.
%let states=AK,AZ,CA,HI,ID,NV,OR,WA;
%macro DTCNT() / parmbuff;
%let i=1;
%put &=syspbuff.;
%let ST=%scan(&SYSPBUFF,&I,%str(%(%),));
%put &=st.;
%do %while (%superq(ST)^=);
%put &=st;
%let i=%eval(&i.+1);
%let ST=%scan(&SYSPBUFF,&I,%str(%(%),));
%end;
%mend DTCNT;
%DTCNT(&STATES);
There is a great paper on how to test for empty macro variables, Chang Chung's Is This Macro Parameter Blank.
For your simple program I find it much easier to just use %length() to test for empty macro variables.
%do %while (%length(&ST));

Nothing happening when running code sas

Does anyone else have this problem? Basically, sometimes when I write a macro and run the code, nothing happens. The log just writes the code you tried to execute in black but it's like SAS is disabled and you have to turn off SAS and turn it back on before it runs properly again. Is there a way around this without having to turn off and on sas.
this is my code:
dm 'clear log';
dm 'clear output';
dm 'odsresults: clear';
libname projet 'C:\Users\MJ-INFO\Desktop\Projet scoring1' ;
/*Extrcation de la base d'etude et creation d'une copie*/
data Examen ;
set projet.base_resiliation_proj ;
run;
/*Contenu de la base*/
proc contents data=Examen;
run;
/*Corespondance entre les formats et les variables */
proc format ;
value $sexe
"1"="homme"
"2"="femme";
run;
/*Applicatation des formats*/
data Examen;
set projet.base_resiliation_proj ;
format sexe $sexe.;
run ;
/*Nous avons 53892 observations et 8 variables dans notre base*/
/*Definition de la variable à expliquer *
%let var_cible=RESIL;
/*Definition des variables explicatives */
%let var_quali=formule sexe;
%let var_quanti=anc_client anc_cont cotisation id nb_cont;
/*Vue sur la variable cible*/
proc freq data=Examen;
table &var_cible;
run;
/*14.42 des contrats sont des fragiles*/
/*Exploration des variables candidates de la base*/
proc freq data=Examen;
table &var_quali;
run;
proc means data=Examen min max mean median nmiss;
var &var_quanti;
run;
/*Traitement des valeurs manquantes/aberrantes*/
data Examen;
set Examen;
if cotisation=-1 then delete;
if cotisation='.' then delete;
if nb_cont=99999 then delete;
run;
/*II.Preparation des donnees*/
/*Etude des liaisons entre variables qualitatives et variable cible */
/*Variables qualitatives : test de Khi-2 & v de Cramer*/
%macro quali(table,var,cible,mod);
/*Representation en terme d'effectif*/
proc gchart data=&table;
vbar3d &var. / sumvar=&cible discrete;
title "Effectifs de la variable &var";
run;
/*Taux de contrat à risque*
proc freq data=&table;
table &var.*&cible / chisq outpct out=pct;
run;
proc gchart data=pct (where=(&cible=&mod));
vbar3d &var. / sumvar=pct_row discrete;
title "Taux de contrats à risque de la variable &var";
run;
quit;
title;
%mend;
%quali(Examen,sexe,&var_cible,1);
Sas show me black execute from running this code:
/*II.Preparation des donnees*/
/*Etude des liaisons entre variables qualitatives et variable cible */
/*Variables qualitatives : test de Khi-2 & v de Cramer*/
%macro quali(table,var,cible,mod);
/*Representation en terme d'effectif*/
proc gchart data=&table;
vbar3d &var. / sumvar=&cible discrete;
title "Effectifs de la variable &var";
run;
I didn't understand why I get black execute even my code has no error when I see the log page ??
Thanks for your help!
Your code:
%macro quali(table,var,cible,mod);
/*Representation en terme d'effectif*/
proc gchart data=&table;
vbar3d &var. / sumvar=&cible discrete;
title "Effectifs de la variable &var";
run;
started to define a macro but never finished. There is no %mend statement at the end, so SAS thinks your still sending it macro code to be compiled. If you add a %mend, it should work.
Most common reasons for SAS feeling non responsive in this way are unclosed macro definition, unclosed comment block, and unmatched quotes. If you google "SAS magic string" you'll find examples of code you can submit to try to recover when you're stuck in this situation. Stuff like:
*';*";*/;%mend;
If you're using Enterprise Guide it automatically adds a magic string every time you submit code. This means you're session won't feel hung. But where you have an unclosed macro definition it can make it harder to recognize,because it looks like everything fan fine. But in reality it didn't execute at all. The magic string can end up hiding the problem. I assume SAS studio also adds a magic string, but I haven't checked.

Transform literal date parameter to SAS date value in macro

I want to create a SAS macro which takes a literal date (eg. '31may2011'd) as parameter. Inside the macro I want to transform this into a SAS date value (eg. 18778).
%macro transLiteralDate2Value(literal=);
%put literal = &literal.;
%put sasdatavalue = ???; /* how to calculate this value ? */
%mend;
%transLiteralDate2Value(literal='31may2011'd);
Is the are elegant way to achieve this? Of course I could do this by parsing the literal string, but I think there must be a better way.
I use SAS 9.1.3
This will work inside or outside of a macro. Don't forget %sysfunc() has a handy optional second parameter which will let you format the output value.
%let report_date = %sysfunc(sum('01JAN2011'd),best.);
or
%let report_date = %sysfunc(putn('01JAN2011'd,best.));
Cheers
Rob
You can do it using the %sysfunc macro function.
%macro transLiteralDate2Value(literal=);
%put literal = &literal.;
%put sasdatavalue = %sysfunc(putn(&literal.,8.));
%mend;
%transLiteralDate2Value(literal='31may2011'd);
It is handy to have a pair of simple conversion macros like mine below. See also my sas-l posting.
%macro date2num(date, informat=anydtdte.);
%*-- strip quotations and postfix d from date literal if any. --*;
%*-- quotations are intentionally doubled to prevent unmatched error --*;
%let date=%sysfunc(prxchange(s/[''""]d?//i,-1,&date));
%sysfunc(inputn(&date,&informat))
%mend date2num;
%macro num2date(num, format=date10., literal=1);
%local n;
%let n = %sysfunc(putn(&num,&format));
%if &literal %then "&n"d; %else &n;
%mend num2date;