How do I call a macro variable in the from clause of proc sql if I wish to use it in a libname?
Let me show you what I mean:
options nofmterr;
libname FRST "/ecm/retail/mortgage/nbk6kra/LGD/data/frst_201312bkts";
libname HELN "/ecm/retail/mortgage/nbk6kra/LGD/data/heln_201312bkts";
libname HELC "/ecm/retail/mortgage/nbk6kra/LGD/data/helc_201312bkts";
%let pathLGD = /new/mortgage/2014Q4/LGD;
%let prod = FRST;
/**************** Segment calculation **************** Date filter to be consistent with model documentation for segmented tables****************/
%macro Performance(prod);
proc sql;
create table lgd_seg_&prod as
select distinct
SegDT_LGD_2013,
min(ScoreDT_LGD_2013) as min_range,
max(ScoreDT_LGD_2013) as max_range,
count(*) as count,
mean(lgd_ncl_adjusted) as LGD_actual,
mean(ScorePIT_LGD_2013) as LGD_pred_pit_1,
mean(ScoreDT_LGD_2013) as LGD_pred_dt_1
from "&prod."scored;
where coh_asof_yyyymm > 200612
group by 1;
quit;
PROC EXPORT DATA=lgd_seg_&prod._fs
OUTFILE= "&pathLGD./lgd_seg.xlsx"
DBMS=XLSX REPLACE;
SHEET="&prod._lgd_seg_fs";
RUN;
%mend;
%Performance(prod=FRST);
%Performance(prod=HELN);
%Performance(prod=HELC);
So in the "from" clause, the macro is supposed to read FRST.scored, HELN.scored, and HELC.scored respectively. Currently it cannot find the file, and if I were to remove the quotation marks, then it'd become "work.FRSTscored".
I hope I've made this clear. Any input and comment is appreciated.
When you want to follow the the resolved value of a macro variable with an immediate additional character you should escape the macro variable with a full stop (.). For example:
%let start = one;
%put &start.two;
%put &start..two;
%put &startend;
onetwo
one.two
WARNING: Apparent symbolic reference STARTEND not resolved.
So your code should read from &prod..scored;.
If you ever need to you can also delay the resolution of a macro variable with double ampersand (&&):
%let end = two;
%let onetwo = three;
%put &&one&end;
%put &&&start&end;
Three
Three
Or:
%let three = inception;
%put &&&&&&&start&end;
inception
Remove quotation marks applied outside the macro variable prod and use two dots after macro variable (one to signify end of macro variable name and second one to specify the table name after the libname reference.
from &prod..scored
Related
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.
I would like to set a dataset by using a reference to dataset name however Iam getting error message: ERROR: File dataset_name123 does not exist(work.dataset123 does exist) What is wrong?
data _null_;
%let product = 'dataset_name123';
set work.&product nobs = row_no;
put row_no;
put &product;
run;
Member names are not quoted. Remove the quotes from your macro variable. In macro code everything is character so there is no need to add quotes around string literals. The quotes become part of the value of the macro variable.
%let product = dataset_name123;
%put &=product;
data _null_;
set work.&product nobs = row_no;
put row_no;
put "&product";
stop;
run;
If you do include quotes in a dataset reference then SAS will interpret it as the physical name of the dataset file itself. So code like:
data want;
set 'dataset_name123';
run;
would look for a filename 'dataset_name123.sas7bdat' in the current working directory.
It is not a great idea to do a %let statement in a data step. Macrovariables and SAS variables are created differently.
There are two problems in this code. First one is quotes around macrovariable, which after resolution will be used for table name and hence your query fails as table names cannot be in quotes .
second one is put statement for macro variable for macro variable to resolve you need %put.
below is modified code.
data class;
set sashelp.class;
run;
data _null_;
%let product = class;
set work.&product nobs = row_no;
put row_no;
%put &product;
run;
I have this code :
%global nb_usag;
%global usager_entr;
%let nb_usag=0;
%syslput nb_usag=&nb_usag;
%let usager_entr=u;
PROC SQL noprint ;
select count(distinct no_usager_entr) into :nb_usag from &lib..INSCRITS_USA_1
;
quit;
data _null_;
if &nb_usag > 0 then do;
call execute
("PROC SQL noprint ;
select distinct no_usager_entr INTO :usager_entr separated by ','
from &lib..INSCRITS_USA_1;")
;
if &usager_entr ne "u" then do;
call prxchange('s/,/\",\"',-1,&usager_entr);
end;
end;
run;
%let usager_entr="&usager_entr";
%syslput usager_entr=&usager_entr;
%put &nb_usag;
%put &usager_entr;
But the code generate this error for the function prxchange:
ERROR 135-185: Attempt to change the value of the constant 's/,/\",\"' in the PRXCHANGE subroutine call.
What I am doing wrong?
I want to modify every , in the variable usager_entr with ",".
For example, if usager_entr = 12121212,34343434,56565656 it will become 12121212","34343434","56565656.
In my case the table &lib..INSCRITS_USA_1 is empty, then nb_usag=0.
Thanks!
Too much fooling around! Instead, create the double quoted list of values directly from Proc SQL
Presuming the list will be used in a later clause with the construct IN (&myList).
%let usager_entr_dq_csv_list = "redundant safety value that will never match anything";
PROC SQL noprint ;
select distinct quote(trim(no_usager_entr))
INTO :usager_entr_dq_csv_list separated by ','
from &lib..INSCRITS_USA_1;
The redundant value is needed because if it were empty you would later generate IN () and have a syntax error.
If the list is being used in pass-through SQL you will want to use the additional arguments of QUOTE function to bound the values with a single quote.
For modify your macro variable from usager_entr = 12121212,34343434,56565656 to "12121212","34343434","56565656", you could use prxchange:
%let usager_entr =12121212,34343434,56565656;
%put &usager_entr;
%let New_usager_entr=%sysfunc(prxchange(s/([1-9]+)/"$1"/, -1,%quote(&usager_entr)));
%put &New_usager_entr;
I have defined macro variable
%let data_names = fuzzy_Data_segment EMWS2.Clus_TRAIN;
Then I have written a macro to extract and print the values from the above macro variable as:
%macro calling_data;
%do i = 1 %to 2;
%let data_name&i = %qscan(&data_names,&i);
%put &&data_name&i;
%end;
%mend;
%calling_data;
My macro code is able print the first name(fuzzy_Data_segment), but, it is only printing the part of the second name(EMWS2). what should I do to print the entire second name
Your issue is that SAS considers a period to be one of the default delimiters in macro variables. In this case, it looks like you want to be using a space to delimit items in data_names, so specify that:
%let data_name&i= %qscan(&data_names,&i., %str( ));
You're also missing semicolons in your %let statement and in your call to calling_data.
Can someone please help me.
I have the code below. It does not generate an error but at the same time does not achieve what I want it to.
The intention is to create macro variables for each cell across a number of columns using a 'Select into'. I think the problem is the fact that the 'Select into' contains macro variables too.
%macro ld_macrovar;
proc sql noprint;
select count(portfolio)
into :a
from split_D;
%do i=1 %to &max_comb.; /*already defined elsewhere -actual value=2 */
select _&i.LGD
into :_&i.LGD1 - :_&i.LGD%left(&a)
from split_D;
%end;
quit;
%mend;
%ld_macrovar;
Thanks
Your macro variables are being assigned to the local scope of the macro. So if you want to access them outside the macro you will have to manually assign them to the global scope. This can be achieved by using the %global statement. Alternatively you can perform the processing that requires the macro variables inside the macro.
You can check the scope of your variables by running %put _ALL_; or %put _USER_.
%macro ld_macrovar(max_comb);
proc sql noprint;
select count(*) into :rows
from split_D;
quit;
%do i = 1 %to &max_comb.;
%do j = 1 %to &rows.;
%global _&i.LGD&j.;
%end;
%end;
proc sql noprint;
%do i = 1 %to &max_comb.;
select _&i.LGD
into :_&i.LGD1 -
from split_D;
%end;
quit;
%mend;
/* Dummy data */
data split_D;
do i = 1 to 10;
_1LGD = i**2;
_2LGD = exp(i);
output;
end;
run;
%ld_macrovar(2);
/* Print out all the user defined macro variables */
%put _USER_;
You can also avoid the need to use %left with &a by adding the trimmed option to your fist into statement (in SAS 9.3 and later or separated by "" in other versions).
A word of caution: If you are planning to use the values for further analysis or there are a lot of rows there ma be a better way to achieve what you want. Macro variables store only text and when the values are stored some precision may be lost. In general it's best to use data sets for moving/manipulating data and macro variables for when you need to parametrise your code.