简体   繁体   中英

Calculating age from birth date in sql

I am executing sql queries using oracle. I need to calculate age from birth date given.

select 
    sname,
    TIMESTAMPDIFF(YEAR, DATEOFBIRTH, CURDATE()) 
from 
    sailors 
where 
    (select 
         MAX(TIMESTAMPDIFF(YEAR, DATEOFBIRTH, CURDATE())) 
     FROM sailors) TIMESTAMPDIFF(YEAR, DATEOFBIRTH, CURDATE())

where dateofbirth is my column name and sailors is table name. However, it is showing error, missing keyword.

Ther where clause is used to provide the condition and you have a select statement there. That's the reason you get the error.

If you need just the diff wrt date of birth, then use

SELECT sname,(DATEOFBIRTH - sysdate) AS "Days"
FROM sailors

That should suffice

Gives the row with max age in Oracle:

select sname, age from (
  select sname, extract(year from current_date) - extract (year from dateofbirth) age,
         row_number() over(order by extract(year from current_date) - extract (year from dateofbirth) desc) rw
  from sailors
) where rw = 1;

extract(year from current_date) - extract (year from dateofbirth) difference in years between to dates

row_number() over(order by age desc) - numerates the rows according to ORDER BY

Usually age is given in whole years. So, months_between() gives the number of whole months between two dates; dividing by 12 gives number of years; and applying a floor() removes the unwanted fraction.

select sname
        , floor(months_between(sysdate, dateofbirth)/12) as age_in_yrs
from sailors
/

If you want to get the oldest sailor(s) then you can deploy this as a sub-query:

with cte as ( select sname
                  , floor(months_between(sysdate, dateofbirth)/12) as age_in_yrs
              from sailors )
select *
from cte
where age_in_yrs = ( select max(age_in_yrs) from cte )
/

Oracle has a wealth of datetime functions, which for historical reasons often have names different from their equivalents in other flavours of RDBMS. Find out more .


'It is showing "not a valid month".'

This can only happen when casting a string to a date. So presumably your DATEOFBIRTH column doesn't have a DATE datatype. And the strings in it don't match the default NLS_DATE_FORMAT. A string like this 12.23.1993 would throw ORA-01843 if the default date format is dd.mm.yyyy

So you need to write an explicit cast, thus:

select sname
        , floor(months_between(sysdate, to_date(dateofbirth, 'dd.mm.yyyy'))/12) as age_in_yrs
from sailors
/

Note that I have had to guess whether your dates are DD.MM or MM.DD because it's not obvious from the sample you give; adjust the mask as you need.

select sname, extract(year from sysdate) - extract (year from dateofbirth ) age
from sailors 

--or 

select to_number(to_char(sysdate,'yyyy') - to_number(to_char( dateofbirth ,'yyyy')) 
from sailors  

Here is a T-SQL that can calculate age of a person. Accurate to the day of birth.

select case 
            when cast(getdate() as date) = cast(dateadd(year, (datediff(year, '1996-09-09', getdate())), '1996-09-09') as date)
                then dateDiff(yyyy,'1996-09-09',dateadd(year, 0, getdate()))
            else dateDiff(yyyy,'1996-09-09',dateadd(year, -1, getdate()))
        end as MemberAge
go

A little more about sql age calculation, as APC pointed it out, integer age can be given by the following expression:

floor(months_between(sysdate, dateofbirth)/12)

But, months_between function treats end of month day specially. And this may raise an issue for leapers (someone born on the 29th of Feb), as taken from Wikipedia: The effective legal date of a leapling's birthday in non-leap years varies between jurisdictions.

Putting in an example, on 28/02/1998, was someone born on 29/02/1988 10 years old or 9? Previous expression would yield 10, but in some areas it's 9.

In Teradata, this expression seems to be commonly used to allow leapers only turn one year old on 1st of March, instead of on 28 Feb, in non-leaping years:

select (extract(year from current_date) - extract(year from BIRTH_DATE) (named YEARS))
+ case when current_date - (YEARS (interval year)) < BIRTH_DATE
then -1 else 0 end

I think this expression should have the same effect and no case when has to been invoked:

floor(least(months_between(CURRENT_DATE, BIRTH_DATE), months_between(CURRENT_DATE - 1, BIRTH_DATE - 1))/12)

I ran the following code to check the validity of this expression in Teradata:

select O.DATEO, N.DATEN,
(EXTRACT(YEAR FROM N.DATEN) - EXTRACT(YEAR FROM O.DATEO) (NAMED YEARS))
      + CASE WHEN ADD_MONTHS( N.DATEN , - YEARS * 12 )  < O.DATEO
THEN -1 ELSE 0 END  AS AGE1,
floor(least(months_between(N.DATEN, O.DATEO), months_between(N.DATEN -1, O.DATEO- 1))/12) as AGE2,
AGE1 - AGE2
from
(select cast(calendar_date as date) as DATEO from sys_calendar.CALENDAR
where calendar_date between date '2000-01-01'  and date '2013-01-01') as O
inner join 
(select cast(calendar_date as date) as DATEN from sys_calendar.CALENDAR
where calendar_date between date '2000-01-01'  and date '2013-01-01'
) as N
on N.DATEN > O.DATEO
where AGE1 <> AGE2;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM