Nested If do statements SAS - arrays

I have a dataset which looks like this:
ID 2017 2018 2019 2020
2017 30 24 20 18
2018 30 24 20 18
2019 30 24 20 18
2020 30 24 20 18
I am looking to create an array based on a few inputs:
%let FixedorFloating = '1 or 0';
%let Repricingfrequency = n Years;
%let LastRepricingDate = 'Date'n;
So far my code looks like this:
data ReferenceRateContract;
set refratecontract;
*arrays for years and flags;
array _year(2017:2020) year2017-year2020;
array _flag(2017:2020) flag2017-flag2020;
*loop over array;
if &FixedorFloating=1;
do i=&dateoflastrepricing to hbound(_year);
/*check if year matches year in variable name*/
if put(ID, 4.) = compress(vname(_year(i)),, 'kd')
then _flag(i)=1;
else _flag(i)=0;
end;
else if &fixedorfloating=0;
do i=&dateoflastrepricing to hbound(_year);
if put (ID,4.)<=compress(vname(_year(i)),,'kd')
then _flag(i)=1;
else if put (ID, 4.) = compress(vname(_year(i-2*i)),, 'kd')
then _flag(i)=1;
else _flag(i)=0;
end;
drop i;
run;
The code works for the original if function but I'd like to make this more dynamic by introducing the else if FixedorFloating=0.
I'm also looking to make my function able to decipher whether the ID is on a year +2i year from the ID. i.e.
if ID=2017 - i'd like a 1 for years 2017, 2019. For ID=2018,
I'd like a 1 for 2018, 2020 and so on hence the
year(I-2*I)
I'm unsure if this is reasonable or incorrect.
The error of the log looks like this:
82 else if &fixedorfloating=0;
____
160
ERROR 160-185: No matching IF-THEN clause.
84 then do i=&dateoflastrepricing to hbound(_year);
____
180
ERROR 180-322: Statement is not valid or it is used out of proper order.
91 else _flag(i)=0;
92 end;
___
161
ERROR 161-185: No matching DO/SELECT statement.
I'm assuming the if do followed by an else-if do isn't structured properly.

the issue is here:
if &FixedorFloating=1;
do i=&dateoflastrepricing to hbound(_year);
the first if is a "gating if", meaning that only records matching the condition are processed.
Try changing to:
if &FixedorFloating=1 then
do i=&dateoflastrepricing to hbound(_year);

data ReferenceRateContract;
set refratecontract;
*arrays for years and flags;
array _year(2017:2020) year2017-year2020;
array _flag(2017:2020) flag2017-flag2020;
*loop over array;
if &FixedorFloating=1
then do i=&dateoflastrepricing to hbound(_year);
/*check if year matches year in variable name*/
if put(ID, 4.) = compress(vname(_year(i)),, 'kd')
then _flag(i)=1;
else _flag(i)=0;
end;
else if &fixedorfloating=0
then do i=&dateoflastrepricing to hbound(_year);
if put (ID,4.)<=compress(vname(_year(i)),,'kd')
then _flag(i)=1;
else if put (ID, 4.) = compress(vname(_year(i-2*i)),, 'kd')
then _flag(i)=1;
else _flag(i)=0;
end;
drop i;
run;
by KurtBremser

Related

Checking if JoinDate is within x amount of days

Using moment, I'm trying to create an if statement to see if their joinDate is within 14 days.
let joinDate = ${moment(member.joinedAt).format("YYYY, MMMM Do dddd, HH:mm:ss")}
That's my current code to format when the user joined.
Basically what I'm saying (if you're not following) is how would I check if joinDate is within the last 14 days?
You may wanna use momentjs diff function to get the days difference between the current date and the input .
A Snippet for your reference
const selectedDate = "2021-08-07";
const date_temp = moment().diff(selectedDate, "days", true);
console.log('Is within 14 days? ',date_temp >= 0 && date_temp <= 14);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

How to parse the query to hours instead of days in usql

I need to update logic to add buffer to to do data for last 24 hours instead of 7 days
DECLARE #todo = #opinion== 0? DateTime.UtcNow.AddDays( - 7) : new DateTime(#opinion);
Tried this with offset but it didn't work for me.
DECLARE #todo = #opinion== 0? DateTime.UtcNow.AddDays(-7) : new DateTimeOffset(#opinion, DateTime.UtcNow.AddHours(-24));
opinion is within the last 7 hours
DECLARE #opinion = DateTime.UtcNow.AddHours(-9);
SELECT ...
WHERE opinion >= DateTime.UtcNow.AddHours(-7) AND opinion <= DateTime.UtcNow;
Missing details for a complete answer.

SAS : How to use loop with date

I need to do inner join with a dataset which has date and month in its name, i.e.
Account_2019_10 (as in Oct 2019).
I need to perform this inner join in a loop for each month from a specific month-year till today's month-year.(i.e. from Sept 2019 till July 2020). Considering the dataset has the month & year in the above format (2019_10 for Oct 2019), how would i perform this loop and append all the results in a group for that month-year?
To change the name of the dataset being referenced you will need to use some code generation. Typically just by using macro variables in place of the dataset name(s).
To loop over dates using an offset value and the INTNX() function. You can use INTCK() to determine how many months to generate.
data _null_;
start = '01OCT2019'd ;
end = '01JUL2020'd ;
length name $32 names $1000;
do offset=0 to intck('month',start,end);
date=intnx('month',start,offset);
name='account_'||translate(put(date,yymm7.),'_','M');
names=catx(' ',names,name);
end;
call symputx('names',names);
run;
Now that you have this list of dataset names you can use it in your code to combine the datasets.
data all;
set &names ;
run;
If your monthly tables do not actually have a variable already that indicates the month you can add one by using the INDSNAME= option of the SET statement. Note that the variable created by that option is not saved so you need to copy the value.
data all;
length dsname $41 ;
set &names indsname=dsname;
month = dsname;
run;
Use the SQL data dictionary to identify the data sets containing a yyyy_mm construct.
Select them into a macro variable that will be used to combine all the data sets in a SET statement with INDSNAME option.
Example:
%macro makefakedata();
%local year month amount;
%do year = 2019 %to 2020;
%do month = 1 %to 12;
data work.account_&year._%sysfunc(putn(&month,z2.));
do id = 1 to 10;
amount = 100 * %sysfunc(monotonic()) + id;
output;
end;
run;
%end;
%end;
%mend;
data work.foo_bar;
set sashelp.class;
run;
%makefakedata;
ods listing;
proc sql noprint;
select
catx('.', libname, memname) as dataset
, input (
cats ( substr ( memname, index(memname,'_')+1 ) , '_01' )
, ? YYMMDD10.
) as month
into
:datasets separated by ' '
, :months separated by ' '
from
dictionary.tables
where libname = 'WORK'
and index(memname,'_')
having
month
;
%put &=datasets;
%put &=months;
data all_month_named_data;
set &datasets indsname=from;
source = from;
month = input (
cats ( substr ( source, index(source,'_')+1 ) , '_01' )
, YYMMDD10.);
format month yymm7.;
run;

Base SAS: Transposing Counts By Date Var

I need to create a summary dataset/report which tracks the flow of these purchases over time.I have a dataset which gives a signup date for an overall service and 9 variables which give the purchase dates for different add on products. If the add on variable dates match the signup date then those add on products were included with the signup package. Any add on variable purchase date that comes after the signup date are products which are purchased during the history of the active account. This is what it looks like:
data have ;
length ID 8
signup_DT 8 preferredhd_tv_estbd_dt 8
ultimate_estbd_dt 8 quant_estbd_dt 8
FullyLoaded_estbd_dt 8 HB_estbd_dt Cin_estbd_dt 8
time_estbd_dt 8 router_estbd_dt internet_estbd_dt 8;
INPUT ID 8
signup_DT : anydtdte9. preferredhd_tv_estbd_dt : anydtdte9.
ultimate_estbd_dt : anydtdte9. quant_estbd_dt : anydtdte9.
FullyLoaded_estbd_dt : anydtdte9. HB_estbd_dt Cin_estbd_dt : anydtdte9.
time_estbd_dt : anydtdte9. router_estbd_dt internet_estbd_dt : anydtdte9. ;;
format signup_DT preferredhd_tv_estbd_dt
ultimate_estbd_dt quant_estbd_dt
FullyLoaded_estbd_dt HB_estbd_dt Cin_estbd_dt
time_estbd_dt router_estbd_dt internet_estbd_dt date9.;
datalines;
98663699 4/7/14 4/9/14 4/7/14 9/12/14 10/15/14 7/7/14 4/7/14 4/7/14 4/12/14 .
33663798 4/11/14 . 4/11/14 . 4/11/14 4/11/14 4/11/14 4/11/14 6/11/14 7/15/14
43663463 5/12/14 5/12/14 5/12/14 9/5/14 9/17/14 . . . . .
77661437 5/16/14 . 5/16/14 . 10/31/14 . 5/16/14 5/16/14 11/16/14 .
85662295 5/29/14 . . 5/29/14 . 6/12/14 . . 11/16/14 .
36656756 6/4/14 . . . 6/4/14 6/4/14 6/12/14 6/4/14 6/4/14 12/4/14
67662646 6/14/14 . 6/14/14 8/31/14 . . 6/17/14 6/14/14 . 6/22/14
55663786 6/26/14 . . . 8/14/14 6/26/14 7/8/14 6/26/14 11/30/14 .
44663191 8/21/14 . 9/30/14 . . . . 1/12/15 . 10/31/14
;
The variables I’m trying to produce are:
Signup month (easy to do)
A count of the total number of signups for that month (easy to do)
A overall count of additional products which included with sign up
A variable which has all add on product values (transposed from original dataset).
A count of the different products purchased on the startup date
A count of add on products purchased after the signup date that were purchased in the same month of the signup date
7.Then month variables which count the additional add on products by month
If I take just April, the output I'm looking for is something like this:
data want ;
length
Sign_up_Month $5
Sign_up_count 8
Initial_Products_total 8
Products $25
Prod_Purchased_on_Signup 8
AddPro_ April_After_SU 8
May 8 June 8 July 8 August 8 September 8 October 8;
INPUT Sign_up_Month $
Sign_up_count
Initial_Products_total
Products $
Prod_Purchased_on_Signup
AddPro_ April_After_SU
May June July August September October;
datalines;
April 2 8 preferredhd_tv_estbd_dt 1
April 2 8 ultimate_estbd_dt 2
April 2 8 quant_estbd_dt 1
April 2 8 FullyLoaded_estbd_dt 1 1
April 2 8 HB_estbd_dt 1
April 2 8 Cin_estbd_dt 2
April 2 8 time_estbd_dt 2
April 2 8 router_estbd_dt 1 1
April 2 8 internet_estbd_dt 1
;
Below is the code I have for the first three vars in the output data set: signup_month, Sign_up_count, Initial_Products_total.
proc sort data=have;
by ID signup_DT; run;
proc transpose data=have out=have (drop=_LABEL_);
by ID signup_DT; run;
data have;
set have;
if signup_DT=COL1 then Initial_flag=1;run;
proc sql;
create table have as
select distinct
count( distinct ID) as Sign_up_count ,
month (signup_DT) as signup_month,
sum (Initial_flag) as Initial_Products
from have
group by month ( signup_DT) ; quit;
I'm having trouble creating the remaining vars: Prod_Purchased_on_Signup, AddPro_ April_After_SU and the counts by month.
I having been experimenting with arrays to try and accomplish this but I've been having trouble.
I'm not certain from your question what level of aggregation you want your counts to be at. But here is a solution if you are looking for summary for each distinct ID and sign-up date. This requires your original input sorted by ID signup_DT.
proc transpose
data = have
out = trans;
by ID signup_DT;
run;
/* Sort for by group processing and regular name order */
proc sort data = trans;
by ID signup_DT _NAME_;
run;
data products (drop = _NAME_ COL1 i);
set trans;
/* For by group processing */
by ID signup_DT;
/* Get the signup month as a word */
signup_month = put(signup_DT, monname.);
/* Make the product list variable to prevent truncation */
length Products $400.;
/* Retain so we can add to the variables as we go down through the group */
retain Products Sign_up_count signups_month0-signups_month4;
/* Set up array reference for later month counts so we can loop */
array som[5] signups_month0-signups_month4;
/* Reset out new variables */
if first.signup_DT then do;
Products = "";
Sign_up_count = 0;
do i = 1 to 5;
som[i] = 0;
end;
end;
/* Add to the listt and count of sign up products */
if signup_DT = COL1 then do;
Sign_up_count + 1;
Products = catx(" ", Products, _NAME_);
end;
/* Otherwise add to the later month counts by checking months seperating the dates */
else do i = 1 to 5;
if intck("month", signup_DT, COL1) = i - 1 then som[i] + 1;
end;
/* Only output once we have completed a group */
if last.signup_DT and Sign_up_count then output;
run;

find the Day of week of a particular date

i have an object which has 2 dates startdate_c and enddate_c .
i need to find a way to find the days of week these dates fall in
For example
startdate = 1 jun 2012 and enddate = 3 jun2012
I need to know which days of the week the days between these dates fall in.
In this example
Mon = false, tue = false, wed = false, thu=false, fri=true,sat=true,sun=true
I want to use this in a Vf page to render the somefields based on the boolean value.
Any pointers would be of great help.
Date has a method called toStartOfWeek which you could leverage, assuming your two dates do lie within the same week you could simply do something like this:
date weekStart = startdate.toStartOfWeek();
list<boolean> days = new list<boolean>();
for(integer i = 0; i < 7; i++)
{
days.add(weekStart.addDays(i) >= startdate && weekStart.addDays(i) <= enddate);
}
A little bit crude, but it'll give you an array of 7 boolean values. For longer/unknown ranges you could use a date cursor and increment that instead of an integer here, but this should get you started. Note, I've not tested this code ;)

Resources