Reputation: 4405
I have a table that contains records of licenses. The table contains a unique license number and the date it was issued.
License # Issue Date
1234 2018-FEB-01
5678 2016-MAR-15
9012 1991-JAN-22
3456 2005-SEP-25
I need to create a report that calculates the age of the license each year since is was issued (rounded down to the nearest year) on a specific date. In this case, sysdate is fine.
So, I am looking for something like this:
License# Year License_Age
1234 2018 0
1234 2019 1
1234 2020 2
5678 2016 0
5678 2017 1
5678 2018 2
5678 2019 3
5678 2020 4
This is going to feed into more query that calculates fees for each year based on a fee schedule. Fees increment ever 5 years or so, however if I can figure out the nuts and bolts of this part of the query, I should be good on the rest.
Here is my basic syntax. I can get the current age of the license for right now, but I really am not sure how to tabulate the age for each year since it was issued:
select floor(months_between(sysdate, a.issue_date) /12) as Years
from
myTable a
where
a.license_number = 1234 --using this specific license number to see if my result returns what I want
Upvotes: 1
Views: 59
Reputation: 167972
You can use a recursive query and add 12 months and then use EXTRACT
to get the year at the end (don't use just the year in the recursive query or you will get rows for current year where the start date would be after the current date):
WITH license_years ( license_no, issue_date, license_age ) AS (
SELECT license_no, issue_date, 0
FROM table_name
UNION ALL
SELECT license_no, ADD_MONTHS( issue_date, 12 ), license_age + 1
FROM license_years
WHERE issue_date <= ADD_MONTHS( SYSDATE, -12 )
)
SELECT license_no,
issue_date AS start_of_license_year,
EXTRACT( YEAR FROM issue_date ) AS year,
license_age
FROM license_years
ORDER BY license_no,
license_age
Which, for your test data:
CREATE TABLE table_name ( License_no, Issue_Date ) AS
SELECT 1234, DATE '2018-02-01' FROM DUAL UNION ALL
SELECT 5678, DATE '2016-03-15' FROM DUAL UNION ALL
SELECT 9012, DATE '1991-01-22' FROM DUAL UNION ALL
SELECT 3456, DATE '2005-09-25' FROM DUAL;
Outputs:
LICENSE_NO | START_OF_LICENSE_YEAR | YEAR | LICENSE_AGE ---------: | :-------------------- | ---: | ----------: 1234 | 2018-02-01 | 2018 | 0 1234 | 2019-02-01 | 2019 | 1 1234 | 2020-02-01 | 2020 | 2 3456 | 2005-09-25 | 2005 | 0 3456 | 2006-09-25 | 2006 | 1 3456 | 2007-09-25 | 2007 | 2 3456 | 2008-09-25 | 2008 | 3 3456 | 2009-09-25 | 2009 | 4 3456 | 2010-09-25 | 2010 | 5 3456 | 2011-09-25 | 2011 | 6 3456 | 2012-09-25 | 2012 | 7 3456 | 2013-09-25 | 2013 | 8 3456 | 2014-09-25 | 2014 | 9 3456 | 2015-09-25 | 2015 | 10 3456 | 2016-09-25 | 2016 | 11 3456 | 2017-09-25 | 2017 | 12 3456 | 2018-09-25 | 2018 | 13 3456 | 2019-09-25 | 2019 | 14 5678 | 2016-03-15 | 2016 | 0 5678 | 2017-03-15 | 2017 | 1 5678 | 2018-03-15 | 2018 | 2 5678 | 2019-03-15 | 2019 | 3 5678 | 2020-03-15 | 2020 | 4 9012 | 1991-01-22 | 1991 | 0 9012 | 1992-01-22 | 1992 | 1 9012 | 1993-01-22 | 1993 | 2 9012 | 1994-01-22 | 1994 | 3 9012 | 1995-01-22 | 1995 | 4 9012 | 1996-01-22 | 1996 | 5 9012 | 1997-01-22 | 1997 | 6 9012 | 1998-01-22 | 1998 | 7 9012 | 1999-01-22 | 1999 | 8 9012 | 2000-01-22 | 2000 | 9 9012 | 2001-01-22 | 2001 | 10 9012 | 2002-01-22 | 2002 | 11 9012 | 2003-01-22 | 2003 | 12 9012 | 2004-01-22 | 2004 | 13 9012 | 2005-01-22 | 2005 | 14 9012 | 2006-01-22 | 2006 | 15 9012 | 2007-01-22 | 2007 | 16 9012 | 2008-01-22 | 2008 | 17 9012 | 2009-01-22 | 2009 | 18 9012 | 2010-01-22 | 2010 | 19 9012 | 2011-01-22 | 2011 | 20 9012 | 2012-01-22 | 2012 | 21 9012 | 2013-01-22 | 2013 | 22 9012 | 2014-01-22 | 2014 | 23 9012 | 2015-01-22 | 2015 | 24 9012 | 2016-01-22 | 2016 | 25 9012 | 2017-01-22 | 2017 | 26 9012 | 2018-01-22 | 2018 | 27 9012 | 2019-01-22 | 2019 | 28 9012 | 2020-01-22 | 2020 | 29
(Note: there is no 2020 row for license no. 3456 as it is not yet September.)
db<>fiddle here
Upvotes: 1
Reputation: 222462
You can use a recursive query for this:
with cte (license#, year, age) as (
select license#, extract(year from issue_date), 0 from mytable
union all
select license#, year + 1, age + 1 from cte where year < extract(year from sysdate)
)
select * from cte order by license#, year
For the first two rows of your sample data, this query yields:
LICENSE# | YEAR | AGE -------: | ---: | --: 1234 | 2018 | 0 1234 | 2019 | 1 1234 | 2020 | 2 5667 | 2016 | 0 5667 | 2017 | 1 5667 | 2018 | 2 5667 | 2019 | 3 5667 | 2020 | 4
Upvotes: 1