Question About SQL Query - sql

I am using the below statement to generate age of a person in Oracle SQL and my question is below.
SELECT TO_NUMBER(TO_CHAR(CURRENT_DATE,'YYYY'))-TO_NUMBER(TO_CHAR(BIRTH_DATE,'YYYY'))
FROM NAME WHERE NAME_ID =NAME_ID
This statement is only correct upto so far that I need a statement which could count months and even days in order to get the age.

Googling for 'oracle get age from dob' returns several answers
select trunc((months_between(sysdate, dob))/12) age
from name;
looks like a good solution (trunc is optional) and
select to_number(to_char(sysdate,'YYYY')) - to_number(to_char(bth_date,'YYYY')) +
decode(sign(to_number(to_char(sysdate,'MMDD')) -
to_number(to_char(bth_date,'MMDD'))),-1,-1,0) age
from name;
is also correct.

You could use the EXTRACT function like
SELECT EXTRACT( YEAR FROM( CURRENT_DATE - BIRTH_DATE )) FROM ...
Substitute YEAR by whatever you need.
/edit I think I misread. If you need higher precisions maybe Intervals could help (http://blagispat.blogspot.com/2007/11/heres-short-article-on-using-intervals.html). (Sry but new users can only post one hyperlink).
SELECT EXTRACT( YEAR FROM( CURRENT_DATE - BIRTH_DATE) YEAR TO MONTH ) FROM ...
or
SELECT EXTRACT( DAY FROM( CURRENT_DATE - BIRTH_DATE) DAY TO SECOND ) FROM ...
which returns days.

Oracle supports arithmetic operations directly on DATE columns:
SELECT SYSDATE - BIRTH_DATE FROM NAME WHERE NAME_ID =NAME_ID
The result here will be a number which expresses the difference in days.
If you want it in months, use this:
SELECT MONTHS_BETWEEN(SYSDATE, BIRTH_DATE) FROM NAME...
If you want it in years, divide MONTHS_BETWEEN by 12.

Related

trunc in Oracle SQL

I try to used TRUNC in SQL Oracle but doens't work . I make a mistake ?
select
TRUNC(cal.DAY_DATE - BIRTHDATE)/ 365 AS EMP_AGE,
from dual
If you want to calculate the number of days between two dates and then divide by 365 and then round down, you can use:
SELECT TRUNC(
(SYSDATE - BIRTHDATE)
/ 365
) AS EMP_AGE
FROM employees;
There are not always 365 days in a year so your calculation is going to be slightly wrong.
It is going to be more accurate to count the number of months using:
SELECT TRUNC(
MONTHS_BETWEEN(SYSDATE, birthdate)
/ 12
) AS emp_age
FROM employees;
See the example below to accomplish what you are wanting to do. Just replace YOUR_TABLE with the table you want, and replace YOUR_BIRTHDAY_COLUMN with the name of the column that contains the birth date in the table you are querying from.
select FLOOR((trunc(sysdate) - (trunc(YOUR_BIRTHDAY_COLUMN)))/365) as AGE from YOUR_TABLE;

How to write a SQL query to retrieve all those customers whose age in months is more than 200 months?

How to write a SQL/Oracle query to retrieve all those customers whose age in months is more than 200 months?
I have a exam on Monday but I am having some confusion with months and dates calculation.
You can use a Query like this for MySQL:
SELECT *
FROM yourTable
WHERE bithdayField <= NOW() - INTERVAL 200 MONTH;
The logic is the same (the date is older than today minus 200 months), but the actual SQL is usually different, because DBMSes have a large variation of syntax in the date/time area.
Standard SQL & MySQL:
WHERE datecol < current_date - interval '200' month
Oracle:
WHERE datecol < add_months(current_date, -200)
In fact Oracle also supports the Standard SQL version, but it's not recommended, because you might get an invalid date error when you do something like '2018-03-31' - interval '1' month. This is based on a (dumb) Standard SQL rule which MySQL doesn't follow: one month before March 31 was February 31, oops, that date doesn't exists.
In Oracle DB, there are two nice functions : months_between and add_months
been used for these type date calculations. For your case, you may use one of the following :
select id, name, surname
from customers
where months_between(trunc(sysdate),DOB)>200;
or
select id, name, surname
from customers
where add_months(trunc(sysdate),-200)>DOB;
demo

Retrieve upcoming birthdays in Postgres

I have a users table with a dob (date of birth) field, in a postgres database.
I want to write a query that will retrieve the next five upcoming birthdays. I think the following needs to be considered -
Sorting by date of birth won't work because the years can be different.
You want the result to be sorted by date/month, but starting from today. So, for example, yesterday's date would be the last row.
Ideally, I would like to do this without functions. Not a deal breaker though.
Similar questions have been asked on SO, but most don't even have an accepted answer. Thank you.
Well, this got downvoted a lot. But I'll post my answer anyway. One of the answers helped me arrive at the final solution, and that answer has been deleted by its owner for some reason.
Anyway, this query works perfectly. It gives the next 5 upcoming birthdays, along with the dates.
SELECT id, name,
CASE
WHEN dob2 < current_date THEN dob2 + interval '1 year'
ELSE dob2
END
AS birthday
FROM people,
make_date(extract(year from current_date)::int, extract(month from dob)::int, extract(day from dob)::int) as dob2
WHERE is_active = true
ORDER BY birthday
LIMIT 5;
You can look at day of year of dob and compare against current date's doy:
SELECT doy
, extract(doy from dob) - extract(doy from current_date) as upcoming_bday
FROM users
WHERE extract(doy from dob) - extract(doy from current_date) >= 0
order by 2
limit 5

How to extract year from HIRE_DATE in my sql

I've written this
SELECT last_name from EMPLOYEES where year(HIRE_DATE)='2000';
but it shows "invalid identifier year".
If you want to get a year of hire date you only have to use
PostgreSQL:
EXTRACT( YEAR FROM hire_date::DATE) = 2000
and for the month you have to use
EXTRACT( MONTH FROM hire_date::DATE) = 12
MySQL:
EXTRACT( YEAR FROM hire_date) = 2000
and for the month you have to use
EXTRACT( MONTH FROM hire_date) = 12
Hope that helped you.
Update Note:Original question was MySQL tagged, response was said to work by Original Poster and response was given in PostgreSQL format, suspect OP should have tagged question as PostgreSQL rather than MySQL. Have clarified this answer to show both working solutions.
Don't extract the year. Instead:
SELECT last_name
FROM EMPLOYEES
WHERE hire_date >= '2000-01-01' AND
hire_date < '2001-01-01';
Why? This version can take advantage of an index.
Extract(year from hire_date)
Above will work fine to get Year , simply replace year to month to get month.

How to calculate ages in BigQuery?

I have two TIMESTAMP columns in my table: customer_birthday and purchase_date. I want to create a query to show the number of purchases by customer age, to create a chart.
But how do I calculate ages, in years, using BigQuery? In other words, how do I get the difference in years between two TIMESTAMPs? The age calculation cannot be made using days or hours, because of leap years, so the function DATEDIFF(<timestamp1>,<timestamp2>) is not appropriate.
Thanks.
First of all, I'd really love BigQuery to have a function which calculates current age based on a date. That seems to be like a very common use case and it's not really easy due to the whole leap year thing.
I found a great article about this issue: https://towardsdatascience.com/how-to-accurately-calculate-age-in-bigquery-999a8417e973
Their final approach is similar to Lars Haugseth's and Saad's answer, but they do not use the DAYOFYEAR part in order to avoid issues with leap years. It also gives you the flexibility not only to calculate the current age, but also the age at a particular date that you pass to the function as argument:
CREATE OR REPLACE FUNCTION workspace.age_calculation(as_of_date DATE, date_of_birth DATE)
AS (
DATE_DIFF(as_of_date,date_of_birth, YEAR) -
IF(EXTRACT(MONTH FROM date_of_birth)*100 + EXTRACT(DAY FROM date_of_birth) >
EXTRACT(MONTH FROM as_of_date)*100 + EXTRACT(DAY FROM as_of_date)
,1,0)
)
Regarding the difference between dates - you could consider user-defined functions (https://cloud.google.com/bigquery/user-defined-functions) with a JavaScript date library, such as Datejs or Moment.js
You can use DATE_DIFF to get the difference in years, but need to subtract by one if the birthday has not yet occured this year:
IF(EXTRACT(DAYOFYEAR FROM CURRENT_DATE) < EXTRACT(DAYOFYEAR FROM birthdate),
DATE_DIFF(CURRENT_DATE, birthdate, YEAR) - 1,
DATE_DIFF(CURRENT_DATE, birthdate, YEAR)) AS age
Here it is in a user defined function:
CREATE TEMP FUNCTION calculateAge(birthdate DATE) AS (
DATE_DIFF(CURRENT_DATE, birthdate, YEAR) +
IF(EXTRACT(DAYOFYEAR FROM CURRENT_DATE) < EXTRACT(DAYOFYEAR FROM birthdate), -1, 0) -- subtract 1 if bithdate has not yet occured this year
);
You can compute the number of days it would be if all years were 365 days long, take the difference, and divide by 365. For example:
SELECT (day2-day1)/365
FROM (
SELECT YEAR(t1) * 365 + DAYOFYEAR(t1) as day1,
YEAR(t2) * 365 + DAYOFYEAR(t2) as day2
FROM (
SELECT TIMESTAMP('20000201') as t1,
TIMESTAMP('20140201') as t2))
This returns 14.0, even though there are intervening leap years. If you want the final result as an integer instead of floating point, you can use the INTEGER() function to cast the result.
Note that if one of the dates is a leap day (feb 29) it will appear to be one year away from march 1, but I think this sounds like the intended behavior.
Another way to calculate age that takes leap years into account is to:
Calculate simple age based on difference in year
Either subtract 1 or not by:
Add difference in years to birthday (e.g. if today is 2022-12-14 and birthday is 2000-12-30, then the "new" birthday becomes 2022-12-30)
Do a DAY-based difference between today and "new" birthday, which either gives you a positive number (birthday passed for this year) or negative number (still has birthday this year)
Subtract 1 year from simple age calculation if number is negative
In BigQuery SQL code this looks like:
SELECT
bd AS birthday
,today
,DATE_DIFF(today, bd, YEAR) AS simpleAge
,DATE_DIFF(today, bd, YEAR) +
(CASE
WHEN DATE_DIFF(today, DATE_ADD(bd, INTERVAL DATE_DIFF(today, bd, YEAR) YEAR), DAY) >= 0
THEN 0
ELSE -1
END) AS age
FROM
(SELECT
PARSE_DATE("%Y-%m-%d", "2000-12-01") AS bd
,CURRENT_DATE("Asia/Tokyo") AS today
)
Outputs:
birthday
today
simpleAge
age
2000-12-30
2022-12-14
22
21