Hi
I'm hoping for some advice on a weird calculation issue we face here at work.
We are trying to determine which month a magazine subscription will expire. We know the current issue (year/month) of the subscription and the number of issues remaining to be sent. There is normally one issue sent per month. Traditionally the subscription will go for 12 months, can start any time of year, though can also go for over 12 months (24/36/etc). Issue numbers start with last 2 digits of the year and last 2 digits is the month number.
i.e. July Issue 2012 = 1207
The business decided to send an extra issue in December which threw all the expiry date calculations out. We have gone from having the following mag issue sequence :
Oct Issue : 1210
Nov Issue : 1211
Dec Issue : 1212
Jan Issue : 1301
Feb Issue : 1302
to
Oct Issue : 1210
Nov Issue : 1211
Dec Issues : 1212 + 1213
Jan Issue : 1301
Feb Issue : 1302
this meant that those subscriptions that had sufficient issues remaining to include the second December issue had a wrong expiry date calculated.
Old calculation
Example : Current issue 1210
Issues to go : 4
Expiry Month : 1302 <<< Wrong
New calculation
Example : Current issue 1210
Issues to go : 4
Expiry Month : 1301 <<< Correct
The code I have posted below works and I will convert this into a function.
The code generates a list of months, duplicates the december month and finds the Expiry Date by matching the Issues to go with the row number.
I am interested if there is a much simpler solution to this problem. This seems like using an elephant gun to shoot clay targets.
DECLARE
v_current_issue CHAR (4) := '1212';
v_issues_to_go int := 15;
v_expire_date CHAR(4) := 0;
BEGIN
if substr(v_current_issue,3,2) = '13' then
v_current_issue := substr(v_current_issue,1,2) + 1 || '01';
v_issues_to_go := v_issues_to_go - 1;
end if;
select full_date
into v_expire_date
from
(select rownum row_val, month_num, full_date
from
(SELECT to_char(ADD_MONTHS (to_date(v_current_issue,'YYMM'), LEVEL - 1),'MM') month_num, to_char(ADD_MONTHS (to_date(v_current_issue,'YYMM'), LEVEL - 1),'YYMM') full_date
FROM DUAL
CONNECT BY LEVEL <= MONTHS_BETWEEN (ADD_MONTHS(to_date(v_current_issue,'YYMM'),v_issu es_to_go + 1), to_date(v_current_issue,'YYMM'))) a,
(select 1 x from dual union all select 2 x from dual ) b
where (b.x = 1 or (b.x = 2 and mod(a.month_num,12) = 0))
order by row_val)
where row_val = v_issues_to_go + 1;
DBMS_OUTPUT.put_line (v_expire_date);
END;
I'm hoping for some advice on a weird calculation issue we face here at work.
We are trying to determine which month a magazine subscription will expire. We know the current issue (year/month) of the subscription and the number of issues remaining to be sent. There is normally one issue sent per month. Traditionally the subscription will go for 12 months, can start any time of year, though can also go for over 12 months (24/36/etc). Issue numbers start with last 2 digits of the year and last 2 digits is the month number.
i.e. July Issue 2012 = 1207
The business decided to send an extra issue in December which threw all the expiry date calculations out. We have gone from having the following mag issue sequence :
Oct Issue : 1210
Nov Issue : 1211
Dec Issue : 1212
Jan Issue : 1301
Feb Issue : 1302
to
Oct Issue : 1210
Nov Issue : 1211
Dec Issues : 1212 + 1213
Jan Issue : 1301
Feb Issue : 1302
this meant that those subscriptions that had sufficient issues remaining to include the second December issue had a wrong expiry date calculated.
Old calculation
Example : Current issue 1210
Issues to go : 4
Expiry Month : 1302 <<< Wrong
New calculation
Example : Current issue 1210
Issues to go : 4
Expiry Month : 1301 <<< Correct
The code I have posted below works and I will convert this into a function.
The code generates a list of months, duplicates the december month and finds the Expiry Date by matching the Issues to go with the row number.
I am interested if there is a much simpler solution to this problem. This seems like using an elephant gun to shoot clay targets.
DECLARE
v_current_issue CHAR (4) := '1212';
v_issues_to_go int := 15;
v_expire_date CHAR(4) := 0;
BEGIN
if substr(v_current_issue,3,2) = '13' then
v_current_issue := substr(v_current_issue,1,2) + 1 || '01';
v_issues_to_go := v_issues_to_go - 1;
end if;
select full_date
into v_expire_date
from
(select rownum row_val, month_num, full_date
from
(SELECT to_char(ADD_MONTHS (to_date(v_current_issue,'YYMM'), LEVEL - 1),'MM') month_num, to_char(ADD_MONTHS (to_date(v_current_issue,'YYMM'), LEVEL - 1),'YYMM') full_date
FROM DUAL
CONNECT BY LEVEL <= MONTHS_BETWEEN (ADD_MONTHS(to_date(v_current_issue,'YYMM'),v_issu es_to_go + 1), to_date(v_current_issue,'YYMM'))) a,
(select 1 x from dual union all select 2 x from dual ) b
where (b.x = 1 or (b.x = 2 and mod(a.month_num,12) = 0))
order by row_val)
where row_val = v_issues_to_go + 1;
DBMS_OUTPUT.put_line (v_expire_date);
END;