Can Somebody please explain me the meaning &, && , % in this SAS code.
I want to convert this code to ECL(HPCC). Thanks
PROC SQL;
create table &RD (compress=binary) as
select a.*,b.Staff_tag2
from &RD a left join (select DISTINCT ucic_id , 1 as Staff_TAG2
from BAL.BAL_&DDMMYYYY1 where prod_code = '102')b
on a.ucic_id=b.ucic_id;
QUIT;
%macro rd();
%do i=1 %to 12;
proc sql;
create table rd.RD_Closed_&&ddmmyyyy&i (compress=binary) as
select V_F_ACCT_ACCT_NUMBER as acct_no,
V_F_ACCT_FIC_CUSTOMER_REF_CODE as ucic_id
from edw.fct_all_accounts_summary
where business_dt eq &&yyyymmdd&i and V_F_ACCT_SOURCE_SYSTEM = 'FINWARERD' AND F_F_ACCT_CLOSED_IND eq 'Y';
quit;
%end;
%mend;
option mprint;
& and && is the beginning of macro variables. They resolve to a value. The value they resolve to depends how they are defined. An example could be:
%let var=test;
in this case &var resolves to test. But there are other ways to initiate macro variables. The %-sign pretty much means that it belongs to the macro languages. There is much to say about SAS macros but i am not sure exactly how much info your after.
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 created 40 plus tables (using a marco, which I just learned how to do) that I would like to apply the Proc Sort statement to. I want each table sorted by the same variable 'Account_Description' (each table contains this variable).
The table names are June_53410_v1, June_53420_v1, June_53430_v1, etc. Can I employ a macro, and if so, how can I, to mitigate having to write a proc sort statement for each table?
Thanks!
I found this sample code online but I'm not really sure how it works
%Macro sorter(dsn, var);
proc sort data=&dsn.;
by &var.;
run;
%mend;
%sorter(sample_dataset, age);
Macro that will be used (proc sort write to work):
%Macro sorter(lib,dsn, var);
proc sort data=&lib..&dsn. out=&dsn.;
by &var.;
run;
%mend;
Get dictionary of tables that contains in name some chars (its maby “June_” instead “AIR”) :
data sashelp_tables;
set sashelp.vtable;
where LIBNAME="SASHELP" and MEMNAME contains "AIR"
;
run;
Write code to string , and execute it for all tables:
data _NULL_;
length code $ 200;
set sashelp_tables;
code=cat('%sorter(',LIBNAME,',',MEMNAME,',AIR);');
call execute(code);
run;
I appreciate everyone's input-I think I found an answer though using this code:
%macro st (ds);
proc sort data = &ds;
by Account_Description;
run;
%mend;
%st(June_53410_v1);
%st(June_53420_v1);
You can use this solution, where lib is libname, mask_table is mask to table(June_ in your task) and var is variable to sort tables:
%macro sorter(lib,mask_table, var); %macro d;%mend d;
%let table_list = 0;
proc sql noprint;
select strip(libname) || '.' || strip(memname),count(memname)
into: table_list separated by ' '
from dictionary.tables
where libname = UPCASE("&lib.") and memname LIKE UPCASE("&mask_table.")||"%";
quit;
%do i=1 %to %sysfunc(countw(&table_list,%str( )));
%let name&i = %scan(&table_list, &i, %str( ));
proc sort data=&&name&i.;
by &var.;
run;
%end;
%mend sorter;
%sorter(WORK,June,Account_Description);
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.
I am stuck trying to iterate through a list of values in a macro %do loop. Each value is supposed to be used as a variable suffix.
The approach is based on SAS documentation: http://support.sas.com/kb/26/155.html
The (simplified) code is:
%macro loop(values);
%let count=%sysfunc(countw(&values));
%do i = 1 %to &count;
%let value=%qscan(values,i,%str(,));
proc sql;
select count(distinct hut_id) as prefix_&value.
from saslib.tl1_results_eval
group by plan_cell;
quit;
%end;
%mend;
%loop(%str(a,b,c,d))
The resulting error message is:
MLOGIC(LOOP): %DO loop beginning; index variable I; start value is 1; stop value is 4; by value
is 1.
MLOGIC(LOOP): %LET (variable name is VALUE)
MPRINT(LOOP): proc sql;
22: LINE and COLUMN cannot be determined.
NOTE 242-205: NOSPOOL is on. Rerunning with OPTION SPOOL might allow recovery of the LINE and
COLUMN where the error has occurred.
ERROR 22-322: Syntax error, expecting one of the following: ',', AS.
MPRINT(LOOP): select count(distinct hut_id) as prefix_a from group by plan_cell;
MPRINT(LOOP): quit;
Interestingly enough, if I remove "prefix_" from "count(distinct hut_id) as prefix_&value." - it works absolutely fine. Unfortunately, I do need the prefix there. Also, as you can see in the log message, the PROC SQL statement does get compiled correctly in the end, but the code errors out before getting executed.
Any ideas what's happening here? Thank you!
You are inserting invisible quoting characters due to the qscan function. Try:
%macro loop(values);
proc sql;
%let count=%sysfunc(countw(&values));
%do i = 1 %to &count;
%let value=%qscan(values,i,%str(,));
select count(distinct hut_id) as prefix_%unquote(&value)
from saslib.tl1_results_eval
group by plan_cell;
%end;
quit;
%mend;
%loop(%str(a,b,c,d))
Note the movement of the proc sql; statement - there are few good reasons to quit; and reinstantiate the SQL procedure between each SQL statement, which incurs overhead..
I need to add a prefix to certain column names in a table. The names at the moment range from _15 to _49 and I would simply like to add the prefix N to give N_15,...,N_49 etc.
I tried the following:
proc sql noprint;
select cats(name,'=','N',name)
into :prefixlist
separated by ' '
from dictionary.columns
where libname = 'WORK' and memname = 'Freq_nais_2006_2010';
quit;
However this does nothing as I just get the message no rows were selected in the log output. What must I change?
Your particular issue is that the WHERE clause is not being fulfilled by any rows, likely because of this: and memname = 'Freq_nais_2006_2010'. Member names are typically capitalized internally in SAS, even if they're not capitalized in your code.
Otherwise your code looks fine, and you should be able to use that &prefixlist. in a PROC DATASETS or data step rename statement. I generally suggest the PROC SQL method as it's easier to customize to specify the variables you want to rename, but of course if you're renaming all of the variables in the dataset the macro works as well.
You're very close:
proc sql noprint;
select cats(name,'=','N',name)
into :prefixlist
separated by ' '
from dictionary.columns
where libname = 'WORK' and memname = 'FREQ_NAIS_2006_2010'
/* and substr(NAME,1,1) = '_' - can add condition on column name pattern */;
quit;
proc datasets lib=WORK nolist nodetails;
modify FREQ_NAIS_2006_2010;
rename
&prefixlist
;
quit;
Changed separator to space for use in PROC DATASETS; MODIFY ... RENAME ... statement.
Side note: the datastep variant answers rewrite the dataset completly, which is ineffective and dangerous for real world usage (big tables), also much less clear on what you're doing.
I managed to find the following code from the sas website (http://support.sas.com/kb/37/433.html):
%macro vars(dsn,chr,out);
%let dsid=%sysfunc(open(&dsn));
%let n=%sysfunc(attrn(&dsid,nvars));
data &out;
set &dsn(rename=(
%do i = 2 %to &n;
%let var=%sysfunc(varname(&dsid,&i));
&var=&chr&var
%end;));
%let rc=%sysfunc(close(&dsid));
run;
%mend vars;
%vars(Freq_nais_2006_2010,N,Freq_nais_2006_2010);
You can just list them in the rename statement in your code, no need for macros or anything else. Though the best idea is avoid it in the first place if you can. See the rename statement below.
data test;
array test(20) _1-_20;
do i=1 to 20;
test(i)=rand('normal', 20);
end;
run;
data test2;
set test;
rename _1-_20 = n_1-n_20;
run;