what is wrong in below code
%let a='2017-01-01';
%let b='2017-12-01';
%let days = %sysfunc(intck(month,"&a"d,"&b"d));
%put days;
Below is the error
ERROR: Argument 2 to function INTCK referenced by the %SYSFUNC or %QSYSFUNC macro function is not a number.
ERROR: Argument 3 to function INTCK referenced by the %SYSFUNC or %QSYSFUNC macro function is not a number.
ERROR: Invalid arguments detected in %SYSCALL, %SYSFUNC, or %QSYSFUNC argument list. Execution of %SYSCALL statement or %SYSFUNC
or %QSYSFUNC function reference is terminated.
67 %put days;
days
Three problems:
Your dates are not SAS date literals. SAS date literals take the format of 'DDMMMYYYY'd or 'DDMMMYY'd For example, 01JAN2018'd, or 01JAN18'd.
You have put quotes around your macro variables that declare the dates, and put double-quotes around them a second time when calling intck.
An & needs to prefix days.
The below code addresses these problems:
%let a=01JAN2017;
%let b=01DEC2017;
%let months = %sysfunc(intck(month,"&a"d,"&b"d));
%put &months;
Because you are calculating the number of months between January 2017 and December 2017, I renamed your macro variable to months.
I guess you want to do this in explicit SQL pass through. for doing that you have to something like this and you can use Teradata specific functions.
/* define date as Teradata Understands*/
%let a= '2017-01-01';
%let b= '2017-12-01';
/* use either of solutions and I do not have Teradata handy, so I did
not explicitly checked this */
SELECT CAST(&b AS DATE) - CAST(&a AS DATE) MONTH(4);
select floor(MONTHS_BETWEEN(date &b - date &a));
Related
I'm compiling order data using a program that has already been built, but am trying to update a section of the code to take today's date minus 61 days and plus 56 days for the respective start and end dates, rather than a manually typed in date as shown below. The current, functional code as well as one of my attempts is below.
The current format that is working and executing is:
/* Set report dates (dd-mm-yyyy) */
%let fore_start = %str(08-SEP-2019);
%let fore_end = %str(03-JAN-2020);
I'm attempting to build something like:
/* Set report dates (dd-mm-yyyy) */
%let fore_start = %str(TODAY()-61);
%let fore_end = %str(TODAY()+56);
I'm looking for help devising a syntactically sound line to solve this problem. Any help would be appreciated!
Try this:
%let fore_start = %sysfunc(putn(%eval(%sysfunc( today() ) - 61), ddmmyyd10.) );
%let fore_end = %sysfunc(putn(%eval(%sysfunc( today() ) + 56), ddmmyyd10.) );
It looks like there's a lot there, but it really isn't. Removing all of the syntax of macro language and converting it into data step functions, here's all you are doing:
fore_start = put(today() - 61, ddmmyyd10.);
fore_end = put(today() + 56, ddmmyyd10.);
There are a few things at play:
In macro language, SAS functions such as putn and today() need to both be enclosed with %sysfunc(). %sysfunc() is your connection to SAS system functions and the macro facility.
%eval will subtract two integers from each other.
putn, another SAS function, will convert the resulting SAS date into your desired format of ddmmyyd10.. putn is required for macro language instead of put.
The date representations you show as being kept in macro variables fore_start and fore_end are actually dd-mmm-yyyy, or format DATE11.
The %sysfunc marco function will invoke a DATA step function and optionally format the result. The INTNX function will perform date arithmetic.
%let fore_start = %sysfunc(intnx(DAY, %sysfunc(today()), -61), DATE11);
%let fore_end = %sysfunc(intnx(DAY, %sysfunc(today()), +56), DATE11);
I am setting up a batch script in SAS, I want it to run monthly and output to table, the code works when running manually but I am having difficulty setting up the macros.
I have created 3 macros, one for the previous month (please ignore the hard coded 12 and the commented out code, I was just testing if it worked or not, the commented out code will remain and the hard coded 12 will be removed when I can get it working), one for the current year and one for the previous year. The issue I will have is that the script grabs month end data, so come January the year will be set to 2020 but the month will be looking for December data.
`%let pmonth = 12 /*%sysfunc(month(%sysfunc(intnx(month,"&sysdate"d ,-1))))*/;`
`%put &pmonth;`
`%let year1 = %sysfunc(year("&sysdate"d));`
`%put &year1;`
`%let year2 = %sysfunc(year(%sysfunc(intnx(year,"&sysdate"d ,-1))));`
`%put &year2;`
`%macro year;
%if &pmonth = 12 %then %do;
&year2;
%end;
%else %do;
&year1;
%end;
%mend;
%year;`
What I would like is for the macro year, which is used in my code, to select correctly between year1 and year2 based on the month macro pmonth. I have played around a bit with the macros but if I'm honest, its not an area of SAS I've used that often.
A little terminology first. Your code has one macro defined, %YEAR. It does have three macro variables named YEAR1, YEAR2 and PMONTH. And there is no macro variable named YEAR that your code is either attempting to create or use. And your code does not have any IF statements. But there is one %IF statement inside the definition of the YEAR macro.
You probably will want to convert your macro variable values into actual DATE values to deal with the year issue. So if your input is two macro variables with YEAR and MONTH you can convert that into a date.
%let year1=2018;
%let month=1;
%let date=%sysfunc(mdy(&month,1,&year1));
Then if you want to find the end of the previous month you can use the date in the INTNX() function call.
%let end_of_prev_month=%sysfunc(intnx(month,&date,-1,e));
Then if you need to you can get the YEAR and MONTH for that new date.
%let year2=%sysfunc(year(&end_of_prev_month));
%let month2=%sysfunc(month(&end_of_prev_month));
Consider the following text value '1/3/2016' from a dataset. This is a badly formatted date value that i cannot correct using ANYDTDTE. as I am on SAS 9.0. In this string the day and month are also the wrong way round. This is actually 03JAN2016 in date9. format
Therefore I have attempted to correct all of the above with the following macro:
%macro date_cats();
proc sql noprint;
select scan(matchdate,1,'/'), scan(matchdate,2,'/'), strip(scan(matchdate,3,'/')) into :month, :day, :year
from test;
quit;
%let padder = 0;
%if %length(&month) < 2 %then
%let month = %sysfunc(cats(&padder., &month.));
%put &month.;
%if %length(&day) < 2 %then
%let day = %sysfunc(cats(&padder., &day.));
%put &day.;
%put %sysfunc(cats(&day., &month., &year.));
%mend;
%date_cats();
The three %put statements produce the following in the log:
01
03
132016
Can anyone tell me in the final put statement why the final CATS statement is either dropping the added '0' character or reverting back to the macro variables being joined before they were padded out?
Thanks
Don't use CATS() to generate macro variables.
First it is totally unneeded since you can concatenate macro variable values by just expanding their values next to each other. Replace
%let month = %sysfunc(cats(&padder., &month.));
with
%let month = &padder.&month.;
Second when trying to evaluate the arguments to functions like CATS() that can take either numeric or character values %SYSFUNC() will attempt to evaluate your strings to see if they are numbers. In your case they are numbers so the leading zeros disappear. In other cases you can cause SAS to generate warning messages.
Third, if you really want to convert a string like 'M/D/Y' into a string like 'DMY' then assuming the string contains valid dates then just use formats to do the conversion.
%let have=1/20/2015 ;
%let want=%sysfunc(inputn(&have,mmddyy10),ddmmyyn8);
CATS is seeing numbers and automatically converting them, unhelpfully.
Generally for macro vars you can use the following
%put &day.&month.&year.;
Hi I am trying to import data (successfully) from a folder that is a date so the file path reads /year/month/date (*today's date)
I am then tweaking some of the data (again successfully). Once that is done I want to export it to a folder that is 29 days forward from the folder I took it from.
Here is my current macro:
%LET TODAY = %SYSFUNC(TODAY());
%PUT &TODAY;
%LET TODAYA = %SYSFUNC(PUTN(&TODAY,DDMMYYn8.));
%PUT &TODAYA;
%LET TWENTYNINE = %SYSFUNC(PUTN(&TODAY.+29,DDMMYYn8.));
%PUT &TWENTYNINE;
%LET T_DATE = %SYSFUNC(PUTN(&TODAY,DDMMYYn8..));
%LET T_YEAR = %SYSFUNC(YEAR(&TODAY));
%LET T_MONTH = %SYSFUNC(MONTH(&TODAY));
%LET P_DATE = %SYSFUNC(PUTN(&TWENTYNINE,DDMMYYn8..));
**%PUT &P_DATE;
%LET P_YEAR = %SYSFUNC(YEAR(&P_DATE));
%LET P_MONTH = %SYSFUNC(MONTH(&P_DATE));**
The P_Date reveals the error:
ERROR: Argument 1 to function MONTH referenced by the %SYSFUNC or %QSYSFUNC macro function is not
a number.
ERROR: Invalid arguments detected in %SYSCALL, %SYSFUNC, or %QSYSFUNC argument list. Execution
of %SYSCALL statement or %SYSFUNC or %QSYSFUNC function reference is terminated.
But I cant get my head around it any help would be massively appreciated.
Imbricating %sysfunc's is handy:
%LET P_YEAR = %SYSFUNC(YEAR(%SYSFUNC(TODAY())+29));
%LET P_MONTH = %SYSFUNC(MONTH(%SYSFUNC(TODAY())+29));
%PUT &P_YEAR &P_MONTH;
Results in:
2016 2
EDIT
(Try solving it by yourself first, but here's a full solution...)
data _null_;
target = today() + 29;
format target YYMMDDS10.;
put target=;
call symput("target", put(target, YYMMDDS10.));
run;
%put ⌖
2016/02/24
If you want to determine the source path to use for today's date then use the TODAY() function. You can apply the YYMMDDS format to have it displayed as YYYY/MM/DD.
%let frompath=%sysfunc(today(),yymmdds10);
If you want to calculate the target path from the source path then you can use the INPUTN() function to convert it back to a date, add 29 and use PUTN() function to convert it back to a string.
%let topath=%sysfunc(putn(29+%sysfunc(inputn(&frompath,yymmdd10)),yymmdds10));
I'm new to SAS so please bear with me.
I have monthly data for the trailing 7 months. It goes through a PROC TRANSPOSE such that the resulting table has columns named FEB2015, MAR2015,...,AUG2015. These columns will change each month I rerun my program so that the earliest month will go from Feb to Mar, etc. in successive months of reruns. I want to be able to reference this "earliest month" later on in the program. For example, I'd like to run a PROC SQL that returns rows that have no values in the FEB2015 column but a value under 1000 in the AUG2015 Column and I'd like to do this based on the fact that the columns are named after last month, and the month 7 months ago.
Here's an example of code I'd be trying to run. Assume the table has columns row_ID, FEB2015, MAR2015, APR2015, MAY2015, JUN2015, JUL2015, AUG2015, all integers.
%let first = put(intnx('month',today(),-7,'begin'), MONYY7.);
%let second = put(intnx('month',today(),-6,'begin'), MONYY7.);
%let last = put(intnx('month',today(),-1,'begin'), MONYY7.);
PROC SQL noprint;
SELECT row_id, &first, &second, &last
FROM mytable
WHERE &first is missing
and &second is not missing
and &last < 1000;
QUIT;
I think the values in the macro variables are just being read as strings and are not being recognized as the name of the column. I've tried wrapping them in NLITERAL() but haven't had any luck.
Thanks!
Of course the macro variable values are strings. Macro variable values are ALWAYS strings. The problem is that your strings are not valid names of variables. Variable names cannot have parentheses or quotes in them. If you want to call a function in macro code you need to nest the call inside of the %SYSFUNC() macro function.
%let first = %sysfunc(intnx(month,%sysfunc(today()),-7,begin), MONYY7.);