Changing FROM statement with a variable - sql

I am trying to change the name of the table I am getting my data from
Like this:
COREPOUT.KUNDE_REA_UDL_202112 --> COREPOUT.KUNDE_REA_UDL_202203
I create my variable like this:
PROC SQL NOPRINT;
SELECT DISTINCT
PERIOKVT_PREV_BANKSL_I_YYMMN6
INTO :PERIOKVT_PREV_BANKSL_I_YYMMN6
FROM Datostamp_PREV_Kvartal;
This is the code I want to use the variable for.
%_eg_conditional_dropds(WORK.QUERY_FOR_KUNDE_REA_UDL_20_0000);
PROC SQL;
CREATE TABLE WORK.QUERY_FOR_KUNDE_REA_UDL_20_0000 AS
SELECT t1.Z_ORDINATE,
(input(t1.cpr_se,w.)) AS KundeNum
FROM COREPOUT.KUNDE_REA_UDL_202203 t1;
QUIT;
I have tried things like:
FROM string("COREPOUT.KUNDE_REA_UDL_",PERIOKVT_PREV_BANKSL_I_YYMMN6," t1";
I hope you can point me in the right direction.

Use & to reference and resolve macro variables into strings (e.g. &PERIOKVT_PREV_BANKSL_I_YYMMN6).
proc sql noprint;
select distinct PERIOKVT_PREV_BANKSL_I_YYMMN6
into :PERIOKVT_PREV_BANKSL_I_YYMMN6
from Datostamp_PREV_Kvartal
;
quit;
proc sql;
create table WORK.QUERY_FOR_KUNDE_REA_UDL_20_0000 AS
select t1.Z_ORDINATE,
(input(t1.cpr_se,w.)) AS KundeNum
from &PERIOKVT_PREV_BANKSL_I_YYMMN6 t1
;
quit;

You can use CALL SYMPUTX() to move values from a dataset into a macro variable.
data _null_;
set Datostamp_PREV_Kvartal;
call symputx('dataset_name',PERIOKVT_PREV_BANKSL_I_YYMMN6);
stop;
run;
Then use the value of the macro variable to insert the dataset name into the code at the appropriate place. So your posted SQL is equivalent to this simple data step.
data QUERY_FOR_KUNDE_REA_UDL_20_0000;
set &dataset_name. ;
KundeNum = input(cpr_se,32.);
keep Z_ORDINATE KundeNum;
run;
Note: I did not see any definition of a user defined informat named W in your posted code so I just replaced it with the normal numeric informat instead since it looked like you where trying to convert a character value into a number.

The solution I ended up with was inspried by #Stu Sztukowski response:
I made a data step to concat the variable and created a macro variable.
data Concat_var;
str_PERIOKVT_PREV_YYMMN6 = CAT("COREPOUT.KUNDE_REA_UDL_",&PERIOKVT_PREV_BANKSL_I_YYMMN6," t1");
run;
PROC SQL NOPRINT;
SELECT DISTINCT
str_PERIOKVT_PREV_YYMMN6
INTO :str_PERIOKVT_PREV_YYMMN6
FROM Concat_var;
Then I used the variable in the FROM statement:
%_eg_conditional_dropds(WORK.QUERY_FOR_KUNDE_REA_UDL_20_0000);
PROC SQL;
CREATE TABLE WORK.QUERY_FOR_KUNDE_REA_UDL_20_0000 AS
SELECT t1.Z_ORDINATE,
(input(t1.cpr_se,w.)) AS KundeNum
FROM &str_PERIOKVT_PREV_YYMMN6;
QUIT;
I hope this helps someone else in the future.

Related

Using macro for formula proc sql in SAS

I need some help with macros in SAS. I want to sum variables (for example, from v_1 to v_7) to aggregate them, grouping by year. There are plenty of them, so I want to use macro. However, it doesn't work (I get only v_1) I would really appreciate Your help.
%macro my_macro();
%local i;
%do i = 1 %to 7;
proc sql;
create table my_table as select
year,
sum(v_&i.) as v_&i.
from my_table
group by year
;
quit;
%end;
%mend;
/* I don't know to run this macro - is it ok? */
data run_macro;
set my_table;
%my_macro();
run;
The macro processor just generates SAS code and then passes onto to SAS to run. You are calling a macro that generates a complete SAS step in the middle of your DATA step. So you are trying to run this code:
data run_macro;
set my_table;
proc sql;
create table my_table as select
year,
sum(v_1) as v_1
from my_table
group by year
;
quit;
proc sql;
create table my_table as select
year,
sum(v_1) as v_1
from my_table
group by year
;
quit;
...
So first you make a copy of MY_TABLE as RUN_MACRO. Then you overwrite MY_TABLE with a collapsed version of MY_TABLE that has just two variables and only one observations per year. Then you try to collapse it again but are referencing a variable named V_2 that no longer exists.
If you simply move the %DO loop inside the generation of the SQL statement it should work. Also don't overwrite your input dataset. Here is version of the macro will create a new dataset name MY_NEW_TABLE with 8 variables from the existing dataset named MY_TABLE.
%macro my_macro();
%local i;
proc sql;
create table my_NEW_table as
select year
%do i = 1 %to 7;
, sum(v_&i.) as v_&i.
%end;
from my_table
group by year
;
quit;
%mend;
%my_macro;
Note if this is all you are doing then just use PROC SUMMARY. With regular SAS code instead of SQL code you can use variable lists like v_1-v_7. So there is no need for code generation.
proc summary nway data=my_table ;
class year ;
var v_1 - v_7;
output out=my_NEW_table sum=;
run;

Dynamize range of SAS PROC SQL SELECT INTO macro creation

I want to put multiple observations into an own macro variable. I would do this by using select into :obs1 - :obs4, however, as count of observations can differ, i would like to dynamize the range and my code looks like this:
proc sql;
create table segments as select distinct substr(name,1,6) as segment from dictionary.columns
where libname = 'WORK' and memname = 'ALL_CCFS' and name ne 'MONTH';
run;
proc sql noprint;
select count(*) into: count from segments;
run;
proc sql noprint;
select segment into :segment_1 - :segment_&count. from dictionary.columns;
run;
However, this doesn't seem to work... any suggestions? Thank you!
Leave last value empty/blank and SAS will create them automatically
Set it to an absurdly large number and SAS will only use what's required
Use a data step to create it where you can dynamically increment your number (not shown).
proc sql noprint;
select segment into :segment_1 -
from dictionary.columns;
run;
proc sql noprint;
select segment into :segment_1 - :segment_999
from dictionary.columns;
run;

Using a SAS macro variable to select all values using the IN operator in PROC SQL

In a SAS script I have a macro variable which is later used in an SQL in statement in a PROC SQL step.
%let my_list = (1,2,3);
proc sql;
select *
from my_table
where var1 in &my_list.
;
quit;
This works fine, but I need some flexibility and also want to be able to select ALL lines without changing the SQL code itself, but just the macro variable.
Is there a trick to specifiy the macro variable so it selects ALL lines still using the IN operator? (avoiding a subquery solution that fills all possible values in the macro variable)
You could change your code to
%let where_clause = var1 in (1,2,3);
proc sql;
select *
from my_table
where &where_clause
;
quit;
And change the macro variable to %let where_clause = 1=1; in order to select all lines.
%let where_clause = 1=1;
proc sql;
select *
from my_table
where &where_clause
;
quit;
OR, if you are adamant about keeping your code unchanged, you could simply change the macro variable as follows in order for your where clause to always be true:
%let my_list = (1) or 1=1;
proc sql;
select *
from my_table
where var1 in &my_list
;
quit;
(dirty but gets the job done)

How to change a date formatted number into number in SQL

I meet a very confusing problem when code SQL in SAS. My code is:
proc sql noprint;
select VDte into :vdate
from test1;
quit;
proc sql;
create table test3 as
select *, cdate>=&vdate. as index
from test2;
quit;
I find all index=1. There should be some index=0 and some index=1. When I use a number instead of macro variable vdate, eg. 17685(02Jun2008) instead of &vdate., it works!
I also checked the VDte. Its type is numeric, format is ddmmyy10.. That is to say VDte is a number stored in SAS! But when give it to &vdate., there is some problem!!
Could someone help me to understand this situation?
Thanks,
Andrea
If your VDte has a SAS date format, you need to "clear" it before storing its value to the macro variable:
proc sql;
select VDte format=8.
into :vdate
from test1;
quit;
Then your comparison should work fine.
Note that you could also use the date9. format for creating your macro variable and then use cdate>="&vdate"d in your second query.

Using proc sql commands in proc fcmp?

I'm new to SAS and trying to create a user defined function that involves proc sql, the simplified version of the function is below;
proc fcmp outlib=work.funcs.test;
function calculate(table1, var1, motherTable);
proc sql noprint;
create table table1 as
select var1
from motherTable;
quit;
return();
endsub;
However, when I run the program I get the following:
ERROR: Subroutine 'calculate' was not terminated with ENDSUB.
ERROR: File WORK.MOTHERTABLE.DATA does not exist.
I am terminating the function with endsub(), and I know that motherTable doesn't exist because it's an argument to the function that hasn't been defined yet. Does anyone know what the problem could be? Thank you so much!
First, what you're doing is probably better done in a macro. That's how you do things like this most of the time in SAS.
%macro calc_func(in_table=, out_table=, var=);
proc sql noprint;
create table &out_table. as
select &var.
from &in_table.
;
quit;
%mend calc_func;
Second of all, you could do this in a user defined function (or a user defined call routine, more likely, as there's nothing being returned here); but you'd have to do it through a macro, if my understanding is right.
Check this paper for more information, or see the below example.
%macro calc_func();
%let table1=%sysfunc(dequote(&table1.));
%let var1=%sysfunc(dequote(&var1.));
%let motherTable=%sysfunc(dequote(&motherTable.));
%put _all_;
proc sql;
create table &table1. as (
select &var1.
from sashelp.&motherTable.)
;
quit;
%mend calc_func;
proc fcmp outlib=work.funcs.test;
function calculate(table1 $, var1 $, motherTable $);
rc = run_macro('calc_func', motherTable, table1, var1 );
return(rc);
endsub;
quit;
options cmplib=work.funcs;
data _null_;
x = calculate('newclass', 'age', 'class');
put x=;
run;
Basically, RUN_MACRO takes the macro name as an argument, and then allows FCMP to create macro variables with the names of the FCMP variables (or passed parameters). However, you have to remove their quotes, which is ... irritating. Good reason not to do this, unless it's truly necessary, I suppose.
The PROC SQL statement is ending the PROC FCMP compilation. You should just write that as a macro.
%macro calculate(table1, var1, motherTable);
proc sql noprint;
create table &table1 as
select &var1
from &motherTable
;
quit;
%mend calculate;