DD MON YYYY to YYMMn6 - sql

I am writing a program in Proc SQL. the program takes various input files, where the filenames change from month to month (i.e. myfile_YYYY_MM or mytable_YYYYMM, or mydata_YY_M).
Most of the program is now dynamic, and the user is asked to input reporting date via a prompt when executing the program.
The "Prompt Date" (&Rep_Date.) in the code has format DD MON YYYY (31may2018), and I need to set up one macro variable transforming this value to format YYMMn6 (i.e. 201805).
The syntax looks like this:
%let Period = input("&Rep_Date."d,YYMMN.);
This worked when trying to create a d9 variable, and for creating a month/year variable, like this:
%let date = "&Rep_Date."d; /*Last day execution month*/
%let year = %sysfunc(year("&Rep_Date."d));
%let month = %sysfunc(month("&rep_Date."d));
for some reason, the same does not work when trying to format the date to YYMMn6.
I also tried creating the variable "Period" in a temporary SAS table like this, but again no luck:
Data dates;
Period = input((&Rep_date.,6.), yymmn6.);
format Period yymmn6.;
Run;
Any ideas on where I am going wrong?

I believe the problem is because of the fact that you are using just the input function in your %let statement.. This won't resolve properly. The right thing would be to use the %sysfunc macro function with the input function. The issue is that sysfunc doesn't work with the input function. Hence, the solution is to use %sysfunc(putn()). Here is an example.
Edit:
Not sure what you're trying to achieve but the %window function (assuming you're using Windows) allows you to take input through a prompt and then create a macro variable from the input. Here is an example:
%global Period;
%window info
#5 #5 'Please enter date:'
#5 #40 _Date 9 attr=underline;
%display info;
%put &_Date.;
%macro da(Rep_Date=&_Date);
%let Period = %sysfunc(putn("&Rep_Date."d,YYMMN.));
%put &Period.;
%mend;
%da();
This should work.

What is going wrong ? You are mixing contexts and misconstruing a representation as a literal (literally - pun literally intended).
In short
Have your macro code utilize the date representation value as the basis for a literal value that is used in a putN() invoked by %sysfunc.
%let Rep_Date = 18-JUN-2018; * some date representation;
%let Period = %sysfunc(PUTN("&Rep_Date."D,YYMMN.));
%put NOTE: Period=%superq(Period);
In Long
From the Glossary in "SAS Help and Documentation" (F1)
SAS date valuean integer that represents a date in SAS software. The integer represents the number of days between January 1, 1960, and another specified date. For example, the SAS date value 366 represents the calendar date January 1, 1961.
SAS date constanta string in the form 'ddMMMyy'd or 'ddMMMyyyy'd that represents a date in a SAS statement. The string is enclosed in quotation marks and is followed by the character d (for example, '6JUL01'd, '06JUL01'd, '6 JUL2001'd, or '06JUL2001'd).
date and time formatinstructions that tell SAS how to write numeric values as dates, times, and datetimes.
date and time informatthe instructions that tell SAS how to read numeric values that are represented as dates, times, and datetimes.
Textual values of the form DD MON YYYY is one form of a representation of a date. The form with four year digits can be input using the instructions inherent in the informat DATE11.. The SAS date literals (SAS date constant) are of the form DDMONYYYYD with or without a variety of spaces, dashes, slashes, etc.
Another code variation similar to the 'In short' would input the date text using a specific format (date11.) instead of relying on the system doing a date literal interpretation.
%let Rep_Date_text_representation = 18/JUN/2018;
%let Rep_Date_value = %sysfunc(inputN(&Rep_Date_text_representation,date11.));
%let Period = %sysfunc(putn(&Rep_Date_Value,yymmn.));
%put NOTE: &=Rep_Date_text_representation ;
%put NOTE: &=Rep_Date_value;
%put NOTE: &=Period;

Related

How to use date of different formats in where condtion to get ouptut in SAS

I have a query which uses date2
call symput('date2',strip(" ' "||put(intx('month',today(),-2,'B'),date9.))||" ' "));
%put &date2;
which basically gives the first day of 2 months prior to running date
and I Have another date which is '30jan2015'd
I want to write a where condition for date column such as
where datecolumn >= '30jan2015'd and datecolumn <= &date2;
When I tried this I am getting an error saying Expression using greater than or equal has components that are of different data types.
Could anyone help me on how I should change the query to make the where condition run, please?
A SAS Date value is either a number, representing number of days from 01-JAN-1960, or a date literal, which is a construct of form "<day>-<month>-<year>"D.
Macro variables are resolved using the & symbol in source code, not $. Are you coming to SAS from a different coding language such as PHP ?
Because your ranges check is endpoint inclusive you can simplify the where statement you are coding by using a BETWEEN operator instead.
Example:
* place an unformatted date value (i.e. data value number) in macro variable;
data _null_;
call symput('date2',intx('month',today(),-2,'B'));
run;
* more code using a date literal and resolved macro variable;
data myDateRangeSubset;
set BigData;
where datecolumn between '30jan2015'd and &date2;
run;
If you are still getting log messages about different data types you will likely have to convert the datecolumn from string to the appropriate SAS date value.
where input(datecolumn,date9.) between '30jan2015'd and &date2;

How to extract records in SAS PROC SQL passthru, filtered by date, but the date is in string format?

I'm trying to extract data from date range (set by start_date and end_date variables defined in the null step).
Usually I would do this using passthru PROC SQL, as follows:
PROC SQL;
CONNECT TO ORACLE AS xxxxx (AUTHDOMAIN="xxxxx" PATH=xxxxx preserve_comments);
CREATE TABLE
work.new_data AS
SELECT
*
FROM
CONNECTION TO xxxxx (SELECT /*+parallel(16)*/ var1, var2, var3
FROM
oracle_data
WHERE date >= &start_date. AND date <= &end_date.);
DISCONNECT FROM xxxxx;
QUIT;
This extracts the data much more efficiently than doing it through a data step or pulling all the data and then filtering it.
The problem is with this particular dataset I'm using, the datetime is stored as a string in the format "DD/MM/YYYY HH:MM:SS". I know how to convert this normally in a data step or such, but the problem is I cannot convert it or interpret it as a date in the PROC SQL passthru stage.
Replacing the WHERE step with any SAS function like below throws an "Oracle Prepare Error" as it doesn't recognize the functions. I've also tried using SQL functions for something similar in the past and they also didn't work and I didn't manage to find a solution.
WHERE DATEPART(INPUT(rtp_date,anydtdtm.)) >= &start_date.)
Is it possible to interpret a string as datetime in the passthru stage and use it for filtering? Or is there perhaps another way to do this which is still more efficient than pulling everything or performing a data step directly onto the oracle data?
When you pass through date criteria to Oracle, one construct for the server side date literal is literally
DATE 'yyyy-mm-dd'
For the task of populating macro variables with source code that is Oracle source code for a date literal you will need to interpret your SAS datetime string, retrieve the date part and render that value as an Oracle date literal.
Example:
options nosource;
data have;
length task start_date_string end_date_string $19;
input task start_date_string& end_date_string&;
datalines;
task1 31/01/2020 08:09:10 02/02/2020 11:00:00
task2 15/03/2019 02:00:00 19/03/2019 23:00:00
;
proc sql noprint;
select start_date_string, end_date_string into :start_date, :end_date
from have where task='task1';
%put &=start_date;
%put &=end_date;
%let s_datepart_val = %sysfunc(inputn(&start_date,ddmmyy10.));
%let e_datepart_val = %sysfunc(inputn(&end_date,ddmmyy10.));
%put &=s_datepart_val;
%put &=e_datepart_val;
%let ora_start_literal = DATE %str(%')%sysfunc(putn(&s_datepart_val,yymmdd10.))%str(%');
%let ora_end_literal = DATE %str(%')%sysfunc(putn(&e_datepart_val,yymmdd10.))%str(%');
%put &=ora_start_literal;
%put &=ora_end_literal;
---------- LOG ----------
START_DATE=31/01/2020 08:09:10
END_DATE=02/02/2020 11:00:00
S_DATEPART_VAL=21945
E_DATEPART_VAL=21947
ORA_START_LITERAL=DATE '2020-01-31'
ORA_END_LITERAL=DATE '2020-02-02'
And an alternate approach to populating the macro variables containing the date literals;
proc sql noprint;
select
'DATE ' || quote(put(input(start_date_string,ddmmyy10.),yymmdd10.),"'")
, 'DATE ' || quote(put(input( end_date_string,ddmmyy10.),yymmdd10.),"'")
into
:ora_start_literal
, :ora_end_literal
from
have
where
task = 'task2'
;
%put &=ora_start_literal;
%put &=ora_end_literal;
---------- LOG ----------
ORA_START_LITERAL=DATE '2019-03-15'
ORA_END_LITERAL=DATE '2019-03-19'
The pass through would utilize the 'literal' macro variables
WHERE date >= &ora_start_literal. AND date <= &ora_end_literal;
We use formats to simplify the process.
Create a format called oracledt. that takes a datetime value and converts it to the format 'mm/dd/yy hh:mm:ss' (including the quotes).
proc format lib=work;
picture oracledt low-high = '''%0m/%0d/%y %0H:%0M:%0S''' (datatype = datetime) ;
run ;
Create a macro variable called my_datetime that contains the current datetime formatted with the above custom format:
%let my_datetime = %sysfunc(datetime(), oracledt.);
%put &=my_datetime;
Output:
MY_DATETIME='02/28/20 09:13:17'
This whitepaper describes the various values you can use when building your own custom format: http://www2.sas.com/proceedings/forum2007/026-2007.pdf
If the format you're after is 'yyyy-mm-dd hh:mm:ss' then your format definition would look like this: '''%Y-%0m-%0d %0H:%0M:%0S'''.
As Richard demonstrates, it is a good practice to keep your dates/datetimes stored as SAS dates/datetime values so that you can work with them, and then create additional variables to be used for the passthrough statement.

SAS Datetime 22.3 to yymmddn8

I am using SAS to bring over a table that sits in a Microsoft SQL Server and and dump it into Hadoop.
The problem I am facing is that the data variable: INSURANCE_DATE.Week_Start_Date is a Datetime 22.3, but needs to be converted into yymmddn8.
I am bringing 3 years of data over, the
entry code piece:
%let three_year_start=%sysfunc(putn(%sysfunc ( intnx(year,%sysfunc(today()), -3)), yymmddn8.)); /* */
%let three_year_end=%sysfunc(putn(%sysfunc(today()), yymmddn8.)); /is today/
works fine, but I am not sure how to format
INSURANCE_DATE.Week_Start_Date properly
so that my where clause works.
%let three_year_start=%sysfunc(putn(%sysfunc (
intnx(year,%sysfunc(today()), -3)), yymmddn8.)); /* */
%let three_year_end=%sysfunc(putn(%sysfunc(today()), yymmddn8.)); /*is
today*/
proc SQL;
create table BA_INS as
SELECT
format (INSURANCE_DATE.Week_Start_Date) yymmdd10.) as Week_Start_Date
FROM
dbo.DIM_INSURANCE_DATE
WHERE
(dbo.DIM_INSURANCE_DATE.Week_Start_Date
between &three_year_start. and &three_year_end.);
quit;
I need a solution as how to convert that datatime 22.3 format into yymmdd10. within the proc sql query
If the source value pulled from SQL Server is, in SAS, presenting itself SAS datetime value, and you want the target value to be pushed to Hadoop from SAS to be as from a SAS date value, you can use the datepart function in SAS.
proc sql;
create table HADOOP.TARGET_TABLE as
select
…
, datepart(Week_Start_Date) as Week_Start_Date format=date9.
…
from
SQLSRV.SOURCE_TABLE
…
;
I don't think the actual date format is important, only that it is one of the SAS date formats. The SAS/Connect engine will examine the SAS column going to target, see the date format and automatically make any tweaks needed to insert the SAS date value as a date value in the target system.
use datepart to take format and then apply format
SELECT
datepart(INSURANCE_DATE.Week_Start_Date) format= yymmdd10. as Week_Start_Date
Not sure what you plan on using the macro variables for, but your are using an extra %SYSFUNC() call. You do not need to call PUTN() to format the value, %SYSFUNC() already will take a format specification.
%let three_year_start=%sysfunc(intnx(year,%sysfunc(today()),-3,b),yymmddn8.);
%let three_year_end=%sysfunc(today(), yymmddn8.);
So this will get you values like 20160101 and 20190123. Note to SAS if you did not enclose those in quotes they would be treated as the numbers 20,160,101 and 20,190,123 rather than anything to do with either date values or datetime values. And if you did enclose them in quotes then they would just be strings.
If you want to just generate a date value then don't bother to format the numbers. Then you will get values like THREE_YEAR_START=20454 and THREE_YEAR_END=21572 which represent the number of days since 1960. Then in your SQL code you could use those. But first you would need to convert your datetime value to a date value. Otherwise you would be comparing apples and oranges (seconds and days).
%let three_year_start=%sysfunc(intnx(year,%sysfunc(today()),-3,b));
%let three_year_end=%sysfunc(today());
...
where datepart(Week_Start_Date) between &three_year_start and &three_year_end
Or you could format your macro variables to look like values that the DATE (or DATETIME) informat could understand and use them as date (or datetime) literals by adding quotes and appropriate suffix letter(s).
DATE Literals
%let three_year_start=%sysfunc(intnx(year,%sysfunc(today()),-3,b),date9.);
%let three_year_end=%sysfunc(today(), date9.);
...
where datepart(Week_Start_Date) between "&three_year_start"d and "&three_year_end"d
DATETIME literals
%let three_year_start=%sysfunc(intnx(dtyear,%sysfunc(datetime()),-3,b),datetime19.);
%let three_year_end=%sysfunc(datetime(), datetime19.);
...
where Week_Start_Date between "&three_year_start"dt and "&three_year_end"dt

PROC SQL: Delete rows by Date with format of e8601dt

Having some issues deleting rows from a data set. They need to be deleted by a date criteria, but the variable is in e8601dt. format. One thing I noticed about the variable is that its a number type variable, but left aligned (not sure if that has relevance or not), so I attempted to substring, and some additional attempts (below)...no success -
PROC SQL;
DELETE *
FROM DATASETS.BATCH_REPORT
WHERE datepart(BATCH_DATE) > '2015-10-01'
;
QUIT;
PROC SQL;
DELETE *
FROM DATASETS.BATCH_REPORT
WHERE BATCH_DATE > '11oct2015'd
;
QUIT;
Assuming there has to be an easy way to call out a value in this format...or will I need to convert this variable to a more compliable format, then do my processing?
OK...did some research. Apparently (and some one please correct me if I am wrong)...to use the e8601dt. format, a date value needs to be multiplied by 86400, then you can apply the format. So.....dividing by 86400 brought me back to the SAS data as an integer. This did the trick :
PROC SQL;
DELETE *
FROM SETS
WHERE ID >= 20372
;
QUIT;
You're close! Date conversions are a pain between systems. The representation of the values depends on the environment configuration.
Within proc SQL, I think you have to specify oracle functions (not the SAS datepart) Looks like you've figured out that Oracle's 'DATE' datatype stores both date&time within the same value. The DATE datatype stores the year (including the century), the month, the day, the hours, the minutes, and the seconds (after midnight). SAS has 2 different date types: date and datetime.
I'd suggest using the oracle to_date() function to compare against a character date, i.e.
WHERE BATCH_DATE > to_date('2015-10-01','yyyy-mm-dd')
If desired, you could use the oracle to_char(BATCH_DATE,'mm-dd-yyyy') to cast the date variable to a text value and then compare on the text value. But you loose some of the comparison power.
....edited due to new info about ...ew... db2 ..... :-)
I'm way NOT a DB2 guy, but maybe something like this?
First, set the date as in: (the date passed to DB2 needs the double quotes):
CALL SYMPUT('INT_DATE',"'"||PUT(sas_date,YYMMDDD10.)||"'");
Then use in the SQL as in:
PROC SQL ;
WHERE BATCH_DATE >= &INT_DATE
https://communities.sas.com/t5/SAS-Procedures/DB2-Date9-format-To-SAS-Serial-Date/td-p/32436

SAS SQL Datepart function returning odd values

I'm having a massive problem with a project that I just can't seem to get right. I'm trying to modify my data variable as its currently in a datetime format. The first data is 30Mar12:00:00:00. I've been advised to use the code below but it returns a value like 30mar60:5:30:00. I just want the date component and have no idea how the data even got exported in this format as it wasn't like this in Microsoft Access. I've tried several mods to this code but again just comes up completely blank or sends an error message.
proc sql; update dataset set date = DATEPART(date); quit;
Any advice would be greatly appreciated.
I'm guessing the variable date is numeric and formatted as DATETIME. Once you've carried out the conversion, just change the format to something like DATE9. A SAS datetime value is the number of seconds since 01 Jan 1960, whereas dates are the number of days since 01 Jan 1960. Both are stored as numbers, so using the correct format to display the value is key. Example below.
data _null_;
a='30Mar12:00:00:00'dt;
b=datepart(a);
c=b;
format a b datetime. c date9.;
put a b c;
run;