SAS how to use a macro variable as a date - sas

I have a global macro variable from another macro which looks like
'01jan2014' when you print it in the log
i.e. there are enforced quotemarks
I want to use this in a proc sql statement but I can't as it doesn't like the variable type.
How do I convert this into a date in the WHERE clause of my proc sql statement?

%let yourdate = 01Feb2015;
%put &yourdate; /* resolve to 01Feb2015 */
proc sql;
select *
from have
where date ge "&yourdate."d;
or
%let yourdate2 = '01Feb2015'd;
proc sql;
select *
from have
where date ge &yourdate2;
I think the first one is better since it won't contain ' in macro variable.

To convert a date string in DDMONYYYY format, simple add a d to the end.
'01jan2014'd
will convert the string to a date.
In your case:
&var.d
will resolve to
'01jan2014'd
which will be interpreted as a date.

Related

Macro variable (date) not working as expected in query

I've several SAS (PROC SQL) queries using a MIN(startdate) and MAX(enddate).
To avoid having to calculate these every time I want to do this once at the beginning and store it in a macro variable but I get an error every time.
What is going wrong or how to achieve this ?
Thanks in advance for the help !
This works:
WHERE DATE BETWEEN
(SELECT MIN(startdate format yymmddn8. FROM work.mydata)
AND (SELECT MAX(enddate format yymmddn8. FROM work.mydata)
DATE format is YYMMDD8n and length is 8.
Creating macro variables:
PROC SQL;
SELECT MIN(startdate), MAX(enddate)
INTO :start_date, :end_date
FROM work.mydata
QUIT;
/*Formatting the macro variable:*/
%macro format(value,format);
%if %datatyp(&value)=CHAR
%THEN %SYSFUNC(PUTC(&value, &format));
%ELSE %LEFT(%QSYSFUNC(PUTN($value,&format)));
%MEND format;
Tried:
WHERE DATE BETWEEN "%format(&start_date, yymmddn8.)" AND "%format(&end_date, yymmddn8.)"
Error message:
ERROR: Expression using equals (=) has components that are of different data types
First, you are missing d when providing date for BETWEEN operator.
WHERE DATE BETWEEN "%format(&start_date, yymmddn8.)"d AND "%format(&end_date, yymmddn8.)"d
But keep in mind tht date string must be in date9. format.
"4NOV2022"d
Second, you dont need to format date for this WHERE condition. Date is numeric and numeric value whould work fine.
WHERE DATE BETWEEN &start_date AND &end_date
If you really want to have date formated you can format it directly inside PROC SQL:
PROC SQL;
SELECT
MIN(startdate) format=date9.,
MAX(enddate) format=date9.
INTO
:start_date,
:end_date
FROM
work.mydata
QUIT;
and then
WHERE DATE BETWEEN "&start_date"d AND "&end_date"d
Note that in a PROC SQL query the format attached to a variable does not carry over to the result of aggregate functions, like MIN() and MAX(), performed on the variable. For numeric variables PROC SQL will use the BEST8. format when converting the number into a string to store into the macro variable. You can remove the extra spaces that causes by adding the TRIMMED keyword.
proc sql noprint;
select min(startdate), max(enddate)
into :start_date trimmed
, :end_date trimmed
from work.mydata
;
quit;
Do not add quotes around the values generated by expanding the macro variables. That would generate a string literal and not a numeric literal.
where date between &start_date and &end_date
If you want the values put into the macro variables by the into syntax to be formatted in some other way you need to attach the format as part of the query.
For example if you wanted the value to be something that could be used to generate a date literal, that is a string that the DATE informat understands, then use the DATE format. Make sure the width used is long enough to include all four digits of the year.
proc sql noprint;
select min(startdate) format=date9.
, max(enddate) format=date9.
into :start_date trimmed
, :end_date trimmed
from work.mydata
;
quit;
...
where date between "&start_date"d and "&end_date"d

SAS macro parameter that is a list

I am trying to create a macro where one of the parameters is a list. My macro includes a proc sql with a where statement that has something like this:
Where Name in ('sarah','ben','adam')
I tried doing something like this:
%MACRO DATA_PULL (name=);
PROC SQL;
SELECT
FROM
Where Name in &name
;
QUIT;
%MEND DATA_PULL;
%DATA_PULL (Name=('sarah','ben','adam'))
but it doesn't work :(
any help appreciated
The SAS in operator does not require commas. This is valid syntax:
where Name in ('sarah' 'ben' 'adam')
so you could have macro invocation with
, names = ('sarah' 'ben' 'adam')
You can also pass commas in a macro parameter by properly quoting the value or value portion. In this case %str can be used.
, names = (%str('sarah','ben','adam'))
If you place the %str outside the in list parenthesis you may also want to escape the parenthesis within the %str
Some example invocations
%macro x(names=);
proc sql;
create table want as
select * from sashelp.class
where name in &names
;
%mend;
%x(names=('Jane' 'James'))
%x(names=(%str('Jane', 'James')))
%x(names=%str(%('Jane', 'James'%)))
you need to using macro quoting functions.
%MACRO DATA_PULL (name=);
PROC SQL;
SELECT *
FROM sashelp.class
Where Name in &name
;
QUIT;
%MEND DATA_PULL;
%DATA_PULL (Name = %str(('Alfred', 'Alice', 'Barbara')))
Trying to put commas in the value of the macro variable is the issue since comma is used to mark the transition between parameter values in the macro call.
What you posted is actually one way to allow the inclusion of commas in the value of a macro parameter. By enclosing the value inside or () the SAS compiler will know that the commas do not mark the start of new parameter values. If you fix your macro so that it generates a valid SELECT statement then it works.
%macro data_pull (name=);
proc sql;
select * from sashelp.class where name in &name;
quit;
%mend data_pull;
%data_pull(name=('Alfred','Alice','ben','adam'))
But the real solution is even easier. Just do not include the commas in the value to begin with. The IN operator does not need them. Then you can add the () in the macro code.
%macro data_pull (name=);
proc sql;
select * from sashelp.class where name in (&name);
quit;
%mend data_pull;
%data_pull(name='Alfred' 'Alice' 'ben' 'adam')
Or you can make your macro a little smarter and then the user can either include the () or not when calling the macro.
%macro data_pull (name=);
proc sql;
select * from sashelp.class
where name in (%scan(&name,1,(),q));
quit;
%mend data_pull;
You can use the SYSPBUFF automatic macro variable, which contains the parameter values you supplied to the macro, including the parentheses and commas. The PARMBUFF option allows one to build a macro to deal with a varying number of parameters.
%macro data_pull / parmbuff;
proc sql;
select *
from sashelp.class
where name in &syspbuff.;
quit;
%mend data_pull;
%data_pull('Alfred','Alice','ben','adam')
In this example, the SYSPBUFF variable is ('Alfred','Alice','ben','adam'), which fits nicely for your SQL query.

Using date macro variable in PROC SQL

I am having trouble getting a macro variable to work correctly in PROC SQL and it doesn't make sense to me.
First, if I generate a query like this:
PROC SQL;
SELECT
a.*
,'31MAR2016' As EVAL_DATE format=date09.
FROM
myTable a
;
it works as expected and puts a date field at the end of the table.
Then, if I do this:
%Let testDate = '31MAR2016'd;
%put &testDate;
PROC SQL;
SELECT
a.*
,&testDate As EVAL_DATE format=date09.
FROM
myTable a
;
this again runs properly, with the log window showing the value of:
'31MAR2016'd
But, if I do this:
%Let Eval_Date = %sysfunc(intnx (month,%sysfunc(inputn(201603,yymmn6.)) ,0,E),date09.);
%Let Eval_date_test = %str(%')&Eval_Date.%str(%')d;
%Put Eval_date_test;
PROC SQL;
SELECT
a.*
,&Eval_date_test As EVAL_DATE format=date09.
FROM
myTable a
;
SAS stops running with the error;
"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, CALCULATED, CASE, EXISTS, INPUT, NOT, PUT, SUBSTRING, TRANSLATE, USER, ^, ~.
ERROR 200-322: The symbol is not recognized and will be ignored."
The log displays the value of &Eval_date_test to be the same '31MAR2016'd as it was in the second example. Note that I created the variable in two steps for clarity, but the same thing happens if you create it in one step.
In case it matters, I am running SAS Enterprise Guide 6.1
Why doesn't this work?
This has to do with how the macro is being dereferenced with the %str() macro. Try the %unquote() macro:
PROC SQL;
SELECT
a.*
, %unquote(&Eval_date_test) As EVAL_DATE format=date09.
FROM
sashelp.cars a
;
quit;
http://support.sas.com/documentation/cdl/en/mcrolref/67912/HTML/default/viewer.htm#p1f5qisx8mv9ygn1dikmgba1lmmu.htm
You are working much too hard and just confusing poor old SAS. Instead of using macro quoting just use the right quote characters to begin with. SAS doesn't care which quote characters you use, but text inside of single quotes is not evaluated for macro triggers and text inside of double quotes is. So '&eval_date'd does not resolve the macro variable reference and "&eval_date"d does.
%let Eval_Date="%sysfunc(intnx(month,%sysfunc(inputn(201603,yymmn6)),0,E),date9)"d;
You're missing a comma after a.*

SAS Macro, passing value as string to where clause

I have a SAS macro below that is not working--- this snippet returns no values because the where statement doesn't work. Anyone have any ideas? I tried adding %str but that didn't work either.
%macro refreshments(beverage_type=);
proc sql;
select
*
where drink_type = '&beverage_type.'
;
quit;
%mend
%refreshments(Sprite);
Thanks.
Macro variables will not resolve in single quotes. You are also missing the FROM clause, and the macro parameter was being provided as positional (instead of name=value pair). Try the following:
%macro refreshments(beverage_type=);
proc sql;
select *
from YOURTABLE
where drink_type = "&beverage_type";
%mend;
%refreshments(beverage_type=Sprite);

why does the MAX function strip the SAS variable format in proc sql?

Consider the following:
data;
format x datetime19.;
x=datetime();
flag='FIRST';
do x=datetime() to x+10 by 1;
output;
flag='';
end;
proc sql noprint;
select x into : test1 from &syslast where flag='FIRST';
select max(x) into: test2 from &syslast;
%put now we see that &test1 is in a different format to &test2;
data _null_; set;
put x=; /* formatted */
call symput('test3',x);
call symput('test4',max(x,sum(x+1000)));
stop;
run;
%put The data step is more consistent - &test3 = &test4;
Seems inconsistent to me. Why does proc sql retain the format in this case? Is this behaviour documented?
There's no way for SAS to know how the result of a function should be formatted. In this case your max() function is simply returning a datetime, but what if there were nested functions or arithmetic inside it. Because of this SAS just treats it as a brand new variable which by default has no format set. If you would like to apply the same format to it you can change your code to this:
select max(x) format=datetime19. into: test2 from &syslast;
In your example, the MAX function creates a new column and when creating new columns, you need to specify all column attributes. So, just add a FORMAT clause to your select statement:
proc sql noprint;
select x into : test1 from &syslast where flag='FIRST';
select max(x) format=datetime19. into: test2 from &syslast;
quit;
%put now we see that &test1 is in a different format to &test2;