stored procedure returns wrong value - mysql

I have a stored procedure that keeps giving me wrong answer. I asked the procedure to return the value of motor insurance. I run the procedure and give me the total of motor insurance premium but if I run it for the 4th time it give me the ageRange select statement value.
I moved the code into a new procedure but still the same.
My code
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `cal_motor_qoute`(in
coverID int , in dob date,
in sumMotor double , out QMsg varchar(200))
BEGIN
declare policy_cover , total , insRatio, ageExtra double;
declare ageRange int;
declare price_list varchar(200);
SELECT DATEDIFF(NOW(),dob) / 365.25 AS ageRange from dual;
if (coverID = 1) then
set policy_cover = 0.002;
elseif (coverID = 2) then
set policy_cover = 0.0025;
elseif (coverID = 3) then
set policy_cover = 0.003;
elseif (coverID = 4) then
set policy_cover = 0.0035;
end if;
if ( ageRange < 25) then
set ageExtra = 0.0005;
else
set ageExtra = 0.000;
end if;
set insRatio = policy_cover + ageExtra;
set total = (sumMotor * insRatio )* 10;
set QMsg = concat('total Premium is: ',total);
select #QMsg;
END
Any help please..

SELECT DATEDIFF(NOW(),dob) / 365.25 AS ageRange from dual;
will not set the variable ageRange, but it will do a select (of the calculated value) and name the column of the resultset ageRange.
The (or rather: one) way to set the value of your variable is to use into:
SELECT DATEDIFF(NOW(),dob) / 365.25 into ageRange from dual;
Although this is probably not the most precise way to calculate the age of a person anyway. You might want to replace
if ( ageRange < 25) then
with
if ( dob > date_sub(now(), interval 25 year) ) then

Related

Need to loop a MySql Query by changing a parameter

I am very new to mysql scripts , I want to execute this query by incrementing 00:00:00 time to 30 minutes .
something like this
Select count(*)
FROM ctrdb.CTR_LINE_ITEM
where LOAD_DATE BETWEEN '2016-05-18 00:00:00' AND '2016-05-18 00:30:00'
order by load_date;
Select count(*)
FROM ctrdb.CTR_LINE_ITEM
where LOAD_DATE BETWEEN '2016-05-18 00:30:00' AND '2016-05-18 00:60:00'
order by load_date;
Can you guys please help me ?
if you wan to achieve this in mysql and want to get separate resultset for each query
then you need to run your query in loop by using stored procedure.
read loop in mysql http://www.mysqltutorial.org/stored-procedures-loop.aspx
or there are not multiple queries then you can use union as well
DELIMITER $$
CREATE PROCEDURE getdata()
BEGIN
DECLARE x INT;
DECLARE maximum INT; # you can use date as well
DECLARE startdate DATE;
DECLARE enddate DATE;
SET x =0;
SET maximum = 10;
SET startdate = '2016-05-18 00:00:00';
loop_label: LOOP
IF x > 10 THEN
LEAVE loop_label;
END IF;
SET x = x + 1;
SET enddate = startdate + INTERVAL 30 MINUTE;
Select count(*) ,startdate
FROM ctrdb.CTR_LINE_ITEM
where LOAD_DATE BETWEEN '2016-05-18 00:00:00' AND '2016-05-18 00:30:00'
order by load_date;
SET startdate = startdate + INTERVAL 30 MINUTE;
END LOOP;
END $$
DELIMITER ;

A sql function that returns true/false with some data calculations problems

I need to create a function in sql that returns 0 or 1 if the "totalOrderSum" is lower than 1000 or higher. The parameters that are going in are #artNr, #orderNr and #amount. The problem is that I have to find the #artNr price from another table and get that price * #amount and after that I have to get the total TotalAmount from one more table and see if (TotalAmount + (#price * #amount) < 1000).
I have some sql code below and I think you know what i want to do with the code.
Many thanks in advance.
CREATE FUNCTION Lab2_spAddOrderLine(#artNr INT,#orderNr INT,#amount) RETURNS BIT
WITH SCHEMABINDING
AS BEGIN
DECLERE #result BIT, #price INT,#totalPrice
IF(
SELECT Price
FROM Lab2_Article
WHERE ArtNr=#artNr AS #price
AND WHERE (
SELECT TotalAmount
FROM Lab2_CostomOrder
WHERE OrderNr = #orderNr AS #totalPrice
AND WHERE ((#totalPrice +(#price * #amount)) < 1000
)
)
SET #result = 1
ELSE
SET #result = 0
RETURN #result
END
DELIMITER //
CREATE PROCEDURE lab2_addOrderLineProcedure
(
IN articleNr INT,
IN orderNr INT,
IN amount INT,
OUT result BIT
)
BEGIN
DECLARE price INT;
DECLARE totalPrice INT;
SET price = (SELECT Price FROM Lab2_Article WHERE ArtNr = articleNr);
SET totalPrice = ((SELECT TotalPrice FROM Lab2_CostomOrder WHERE orderNr = orderNr) + (price * amount));
IF totalPrice < 1000 THEN
INSERT INTO Lab2_OrderLine VALUES (articleNr, orderNr, amount);
SET result = 1;
ELSE
SET result = 0;
END IF;
END //
DELIMITER ;
There are so many errors in your code. Try the following:-
CREATE FUNCTION Lab2_spAddOrderLine(`artNr` INT, `orderNr` INT, `amount` int)
RETURNS BIT
BEGIN
DECLARE `result` BIT, `price` INT, `totalPrice` INT
IF(
SELECT Price
FROM Lab2_Article
WHERE ArtNr=`artNr` AS #price
AND (
SELECT TotalAmount
FROM Lab2_CostomOrder
WHERE OrderNr = `orderNr` AS `totalPrice`
AND ((`totalPrice` +(`price` * `amount`)) < 1000
)
)
SET `result` = 1
ELSE
SET `result` = 0
RETURN `result`
END;

I want to optimize this SQL Query

I have query like this:
DELIMITER $$
USE `kpbaru`$$
DROP PROCEDURE IF EXISTS `getAllUmurPegawai`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `getAllUmurPegawai`(IN id_user VARCHAR(20),i_tahun INT)
BEGIN
DECLARE currdate INT;
DECLARE birthdate INT;
DECLARE numRows INT;
DECLARE numIteration INT;
DECLARE tempMonth INT;
DECLARE umur INT;
SET numRows = (SELECT COUNT(*) FROM pegawai);
SET numIteration = 1;
WHILE numIteration <= numRows DO
SET currdate = i_tahun;
SET birthdate = (SELECT EXTRACT(YEAR FROM (SELECT TGL_LAHIR FROM pegawai WHERE INDEXING = numIteration AND ID_USER=id_user)));
SET umur = currdate - birthdate;
SET tempMonth = (SELECT EXTRACT(MONTH FROM (SELECT TGL_LAHIR FROM pegawai WHERE INDEXING = numIteration AND ID_USER=id_user)));
IF umur < 56 THEN
UPDATE pegawai SET pegawai.STATUS_PEGAWAI='Belum Pensiun',pegawai.BULAN_PENSIUN=tempMonth,STATUS_PENSIUN=1 WHERE pegawai.INDEXING = numIteration AND ID_USER=id_user;
ELSE
IF umur = 56 THEN
UPDATE pegawai SET pegawai.STATUS_PEGAWAI='Pensiun',pegawai.BULAN_PENSIUN=tempMonth,STATUS_PENSIUN=1 WHERE pegawai.INDEXING = numIteration AND ID_USER=id_user;
ELSE
UPDATE pegawai SET pegawai.STATUS_PEGAWAI='Pensiun',pegawai.BULAN_PENSIUN=tempMonth,STATUS_PENSIUN=0 WHERE pegawai.INDEXING = numIteration AND ID_USER=id_user;
END IF;
END IF;
SET numIteration = numIteration + 1;
END WHILE;
END$$
DELIMITER ;
i want to optimize this query, because this query will search each age in eeach people. This query runs very slow if we have big data (>1000 rows). Any one know how to optimize it?
I've tried some query like this:
UPDATE pegawai AS p LEFT JOIN(SELECT INDEXING, CAST(CASE WHEN (i_tahun - EXTRACT(YEAR FROM(SELECT TGL_lAHIR FROM pegawai WHERE ID_USER=id_user))) < 56 THEN 'Belum Pensiun' ELSE 'Pensiun' END AS VARCHAR(20))AS statusPegawai, EXTRACT(MONTH FROM(SELECT TGL_LAHIR FROM pegawai WHERE ID_USER=id_user))AS bulanPensiun, CAST(CASE WHEN (i_tahun - EXTRACT(YEAR FROM(SELECT TGL_lAHIR FROM pegawai WHERE ID_USER=id_user))) <= 56 THEN 1 ELSE 0 END AS INT)AS statusPensiun FROM pegawai WHERE ID_USER=id_user GROUP BY INDEXING)AS m
ON p.ID_USER = m.ID_USER
SET p.STATUS_PEGAWAI = m.statusPegawai, p.BULAN_PENSIUN = m.bulanPensiun, p.STATUS_PENSIUN = m.statusPensiun
WHERE p.ID_USER = id_user;
but it still wrong. Here the error is:
Query :
CREATE DEFINER=`root`#`localhost` PROCEDURE `getAllUmurPegawai`(in id_user varchar(20),i_tahun int) BEGIN DECLARE currdate INT;...
Error Code : 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'varchar(20))as statusPegawai, extract(month from(select TGL_LAHIR from pegawai w' at line 29
Solution will be apreciated! :D
You cannot cast to varchar use char instead.
From the mysql documentation
The CONVERT() and CAST() functions take an expression of any type and produce a result value of a specified type.
The type for the result can be one of the following values:
- BINARY[(N)]
- CHAR[(N)]
- DATE
- DATETIME
- DECIMAL[(M[,D])]
- SIGNED [INTEGER]
- TIME
- UNSIGNED [INTEGER]
If I am reading your query correctly I think you can do this in a single update statement for a user:-
UPDATE pegawai
SET STATUS_PEGAWAI = IF(i_tahun - YEAR(TGL_LAHIR) < 56, 'Belum Pensiun', 'Pensiun'),
BULAN_PENSIUN = MONTH(TGL_LAHIR),
STATUS_PENSIUN = IF(i_tahun - YEAR(TGL_LAHIR) <= 56, 1, 0)
WHERE ID_USER=id_user

Calculate age in MySQL (InnoDB)

If I have a person's date of birth stored in a table in the form dd-mm-yyyy, and I subtract it from the current date, what format is the date returned in?
How can I use this returned format to calculate someone's age?
You can use TIMESTAMPDIFF(unit, datetime_expr1, datetime_expr2) function:
SELECT TIMESTAMPDIFF(YEAR, '1970-02-01', CURDATE()) AS age
Demo
If the value is stored as a DATETIME data type:
SELECT YEAR(CURRENT_TIMESTAMP) - YEAR(dob) - (RIGHT(CURRENT_TIMESTAMP, 5) < RIGHT(dob, 5)) as age
FROM YOUR_TABLE
Less precise when you consider leap years:
SELECT DATEDIFF(CURRENT_DATE, STR_TO_DATE(t.birthday, '%d-%m-%Y'))/365 AS ageInYears
FROM YOUR_TABLE t
SELECT TIMESTAMPDIFF (YEAR, YOUR_COLUMN, CURDATE()) FROM YOUR_TABLE AS AGE
Check the demo image below
Simple but elegant..
Use:
select *,year(curdate())-year(dob) - (right(curdate(),5) < right(dob,5)) as age from your_table
In this way, you consider even month and day of birth in order to have a more accurate age calculation.
select floor(datediff (now(), birthday)/365) as age
Simply:
DATE_FORMAT(FROM_DAYS(TO_DAYS(NOW())-TO_DAYS(`birthDate`)), '%Y')+0 AS age
Since the question is being tagged for mysql, I have the following implementation that works for me and I hope similar alternatives would be there for other RDBMS's. Here's the sql:
select YEAR(now()) - YEAR(dob) - ( DAYOFYEAR(now()) < DAYOFYEAR(dob) ) as age
from table
where ...
Try this:
SET #birthday = CAST('1980-05-01' AS DATE);
SET #today = CURRENT_DATE();
SELECT YEAR(#today) - YEAR(#birthday) -
(CASE WHEN
MONTH(#birthday) > MONTH(#today) OR
(MONTH(#birthday) = MONTH(#today) AND DAY(#birthday) > DAY(#today))
THEN 1
ELSE 0
END);
It returns this year - birth year (how old the person will be this year after the birthday) and adjusts based on whether the person has had the birthday yet this year.
It doesn't suffer from the rounding errors of other methods presented here.
Freely adapted from here
Simply do
SELECT birthdate, (YEAR(CURDATE())-YEAR(birthdate)) AS age FROM `member`
birthdate is field name that keep birthdate name
take CURDATE() turn to year by YEAR() command
minus with YEAR() from the birthdate field
This is how to calculate the age in MySQL:
select
date_format(now(), '%Y') - date_format(date_of_birth, '%Y') -
(date_format(now(), '00-%m-%d') < date_format(date_of_birth, '00-%m-%d'))
as age from table
You can make a function to do it:
drop function if exists getIdade;
delimiter |
create function getIdade( data_nascimento datetime )
returns int
begin
declare idade int;
declare ano_atual int;
declare mes_atual int;
declare dia_atual int;
declare ano int;
declare mes int;
declare dia int;
set ano_atual = year(curdate());
set mes_atual = month( curdate());
set dia_atual = day( curdate());
set ano = year( data_nascimento );
set mes = month( data_nascimento );
set dia = day( data_nascimento );
set idade = ano_atual - ano;
if( mes > mes_atual ) then
set idade = idade - 1;
end if;
if( mes = mes_atual and dia > dia_atual ) then
set idade = idade - 1;
end if;
return idade;
end|
delimiter ;
Now, you can get the age from a date:
select getIdade('1983-09-16');
If you date is in format Y-m-d H:i:s, you can do this:
select getIdade(substring_index('1983-09-16 23:43:01', ' ', 1));
You can reuse this function anywhere ;)
I prefer use a function this way.
DELIMITER $$ DROP FUNCTION IF EXISTS `db`.`F_AGE` $$
CREATE FUNCTION `F_AGE`(in_dob datetime) RETURNS int(11)
NO SQL
BEGIN
DECLARE l_age INT;
IF DATE_FORMAT(NOW( ),'00-%m-%d') >= DATE_FORMAT(in_dob,'00-%m-%d') THEN
-- This person has had a birthday this year
SET l_age=DATE_FORMAT(NOW( ),'%Y')-DATE_FORMAT(in_dob,'%Y');
ELSE
-- Yet to have a birthday this year
SET l_age=DATE_FORMAT(NOW( ),'%Y')-DATE_FORMAT(in_dob,'%Y')-1;
END IF;
RETURN(l_age);
END $$
DELIMITER ;
now to use
SELECT F_AGE('1979-02-11') AS AGE;
OR
SELECT F_AGE(date) AS age FROM table;
There is two simple ways to do that:
 
select("users.birthdate",
DB::raw("FLOOR(DATEDIFF(CURRENT_DATE, STR_TO_DATE(users.birthdate, '%Y-%m-%d'))/365) AS age_way_one"),
 
select("users.birthdate",DB::raw("(YEAR(CURDATE())-YEAR(users.birthdate)) AS age_way_two"))

How to get an age from a D.O.B field in MySQL?

I need to calculate the age of a "customer" from their date of birth.
I have tried to use the following:
DATEDIFF(year, customer.dob, "2010-01-01");
But it does not seem to work.
Any ideas? I KNOW it is going to be something simple!
Thanks
SELECT DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(dob, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(dob, '00-%m-%d')) AS age
Use Mysql recommended :
TIMESTAMPDIFF(YEAR, dob, CURDATE()) AS age;
Usage in a query :
SELECT name, dob, TIMESTAMPDIFF(YEAR, dob, CURDATE()) AS age FROM pet;
Ref: http://dev.mysql.com/doc/refman/5.0/en/date-calculations.html
A few ways:
select DATEDIFF(customer.dob, '2010-01-01') / 365.25 as age
SELECT DATE_FORMAT(FROM_DAYS(DATEDIFF(customer.dob,'2010-01-01')), ‘%Y’)+0 AS age
Hope this helps you
Bryan Denny's answer is more correct than the accepted answer (I wasn't sure how to put this in somewhere other than a new answer; this is my first time on StackOverflow).
Marcos' first attempt:
select DATEDIFF(customer.dob, '2010-01-01') / 365.25 as age
will firstly yield a negative result (the arguments to DATEDIFF are in the wrong order), and secondly will produce inaccurate results for some dates, e.g.:
SELECT DATEDIFF('2010-05-11','1984-05-11') / 365.25 AS age
produces the result:
25.9986
You can't just simply always round up, because that will also cause inaccurate results for other inputs.
Marcos' second attempt:
SELECT DATE_FORMAT(FROM_DAYS(DATEDIFF(customer.dob,'2010-01-01')), ‘%Y’)+0 AS age
Again, the arguments are in the wrong order, except this time instead of just producing a negative number, the FROM_DAYS() function does not work correctly with negative input. Secondly, if we look closer at the output of the FROM_DAYS() function:
select from_days(datediff('2010-09-16','1984-05-11'));
The result of the above is:
0026-05-08
which is literally "8th of May, Year 26 (after 0)". Keep in mind that for datetime types, there is no month "0", so if you wanted to use this format to measure a date interval with months included, you'd have to subtract 1 from the month. Similarly, with the day component, there is no "0", so the result is not what you'd expect for this problem when the date happens to be the birthday:
select from_days(datediff('2010-05-11','1984-05-11'));
produces:
0025-12-31
which if we shorten using Marcos' date formatting gives us "25", which is an incorrect calculation of age.
Bryan Denny's answer is correct in all these edge cases. His formula is quite clever:
SELECT DATE_FORMAT(reference, '%Y') - DATE_FORMAT(birthdate, '%Y') - (DATE_FORMAT(reference, '00-%m-%d') < DATE_FORMAT(birthdate, '00-%m-%d')) AS age
The first part calculates the difference in years between the two dates. So if we take "2010" and "1984" as reference and birthdate respectively, the result is "26". The second part then calculates essentially "Does the birthdate month and day occur after the reference month and day?" If it does, it "hasn't happened yet", so we need to subtract an additional 1 from the year difference to make up for this. This is taken care of by the result of the < comparison, which returns 1 if true and 0 if false.
So, full examples:
1)
Reference date: 2010-05-10;
Birthdate: 1984-05-11
Year difference = 2010 - 1984 = 26
Month and day comparison: May 10th < May 11th? Yes => subtract an additional year
Calculated age: 25 years
2)
Reference date: 2010-05-11;
Birthdate: 1984-05-11
Year difference = 2010 - 1984 = 26
Month and day comparison: May 11th < May 11th? No => subtract 0
Calculated age: 26 years
I hope this makes things clearer for people!
The below sql works fine for me. Always use CURRENT_DATE with dob to calculate the actual age .
SELECT
DATE_FORMAT(
FROM_DAYS(
DATEDIFF(CURRENT_DATE, dob)
),
'%y Years %m Months %d Days'
) AS age
FROM
users
The easy way:
timestampdiff( YEAR, birth_date, now() ) AS age
SELECT *, YEAR(CURDATE()) - YEAR(birthdate) AS age FROM user;
I found some useful queries from below article for calculating age :-
http://www.gizmola.com/blog/archives/archives/107-Calculate-a-persons-age-in-a-MySQL-query.html
DELIMITER $$ DROP FUNCTION IF EXISTS `test`.`_AGE` $$
CREATE FUNCTION `_AGE`(in_dob datetime) RETURNS VARCHAR(100)
NO SQL
BEGIN
DECLARE l_age VARCHAR(100);
DECLARE YEARS INT(11);
DECLARE MONTHS INT(11);
DECLARE DAYS INT(11);
DECLARE DIFFS FLOAT;
SET DIFFS=DATEDIFF(CURRENT_DATE(),in_dob) /365.25;
SET YEARS=FLOOR(DIFFS) ;
SET MONTHS=FLOOR((DIFFS - YEARS)*365.25/30.4375) MOD 12;
SET DIFFS=((DIFFS - YEARS)*365.25/30.4375);
SET DAYS=CEIL(((DIFFS-MONTHS)*30.4375)) MOD 31;
SET l_age=CONCAT(YEARS, " Year ",MONTHS," Month ",DAYS," Days");
RETURN(l_age);
END $$
DELIMITER ;
SELECT _Age(CAST('1980-07-16' AS DATE));
DATE_FORMAT(FROM_DAYS(DATEDIFF(CURDATE(),'1869-10-02')), '%Y')+0 AS age;
Above MySQL query has been tested and verified. It will give you exact age in years. I have taken this idea from Marcos answer and switched DATEDIFF() parameters.
If you want years, months and days like "26 years 4 months and 27 days" then following is the age function for you:
delimiter $$
create function age(dob date)
returns varchar(30)
deterministic
begin
declare years int default 0;
declare months int default 0;
declare days int default 0;
declare today date default curdate();
set years = timestampdiff(year, dob, today);
set months = timestampdiff(month, dob, today - interval years year);
set days = timestampdiff(day, dob, today - interval years year - interval months month);
return (concat(years, ' years ', months,' months and ', days,' days'));
end$$
delimiter;
We are calculating the age from current date so I set today to curdate().
Now we are getting our years, months and days as following.
years: We get the difference in years from today to date of birth.
months: First we subtract the years from the today so that we only
get months that are extra from the years and then find the difference in
months from date of birth. Here "years" is the variable and "year" is interval type.
days: And here we subtract years and months that we
have already calculated from today which is current date then find
the diff in days from birth. Here "months" is the variable and "month" is interval type.
You can use datetime instead of date as argument if you want also you can format the return values as you like.
DROP FUNCTION IF EXISTS FN_GetDuration;
CREATE FUNCTION `FN_GetDuration`(p_STARTDATE DATETIME, p_ENDDATE DATETIME) RETURNS varchar(200) CHARSET utf8
DETERMINISTIC
BEGIN
DECLARE v_DAYS INT;
DECLARE v_MONTHS INT;
DECLARE v_YEARS INT;
DECLARE v_BASEMONTH INT;
DECLARE v_TOTALDAYS INT;
DECLARE v_STYRMONTHDAYS INT;
DECLARE v_ENYRMONTHDAYS INT;
DECLARE v_STYRMONTHS INT;
DECLARE v_ENYRMONTHS INT;
DECLARE v_DATESTRING VARCHAR(50);
DECLARE v_FROMDATE DATETIME;
DECLARE v_TODATE DATETIME;
DECLARE v_ENDMONTH INT(10);
DECLARE v_STARTMONTH INT(10);
DECLARE v_TempValue Varchar(10);
DECLARE v_Year Varchar(2);
DECLARE v_Month Varchar(2);
DECLARE v_Day Varchar(2);
SET v_BASEMONTH = 12; SET v_DAYS = 0; SET v_MONTHS=0; SET v_YEARS=0;
IF p_STARTDATE <= p_ENDDATE
THEN
IF p_STARTDATE <> p_ENDDATE
THEN
SET v_TOTALDAYS = FN_TotalDaysOfMonth(p_STARTDATE);
SET v_STYRMONTHDAYS = v_TOTALDAYS - DAY(p_STARTDATE) + 1;
SET v_ENYRMONTHDAYS = DAY(p_ENDDATE);
SET v_DAYS = v_STYRMONTHDAYS + v_ENYRMONTHDAYS;
END IF;
IF p_STARTDATE = p_ENDDATE
THEN
SET v_DAYS = 1;
END IF;
IF v_DAYS > v_TOTALDAYS
THEN
SET v_MONTHS=1;
SET v_DAYS = v_DAYS-v_TOTALDAYS;
END IF;
IF YEAR(p_STARTDATE) <> YEAR(p_ENDDATE)
THEN
SET v_STYRMONTHS = v_BASEMONTH - MONTH(p_STARTDATE);
SET v_ENYRMONTHS = MONTH(p_ENDDATE)-1;
SET v_MONTHS = v_MONTHS + v_STYRMONTHS + v_ENYRMONTHS;
SET v_DATESTRING = CONCAT(((YEAR(p_STARTDATE))+1 ) , '-01-01 ');
SET v_FROMDATE = v_DATESTRING;
SET v_DATESTRING = CONCAT(((YEAR(p_ENDDATE))-1 ) , '-12-31 ');
SET v_TODATE = v_DATESTRING;
IF YEAR(v_TODATE)<> YEAR(v_FROMDATE)
THEN
SET v_YEARS = (YEAR(v_TODATE)- YEAR(v_FROMDATE))+1;
ELSE
SET v_YEARS = 1;
END IF;
IF v_MONTHS >= v_BASEMONTH
THEN
SET v_YEARS = v_YEARS + 1;
SET v_MONTHS = v_MONTHS - v_BASEMONTH;
END IF;
ELSE
SET v_ENDMONTH = MONTH(p_ENDDATE);
SET v_STARTMONTH = MONTH(p_STARTDATE);
IF p_STARTDATE <> p_ENDDATE
THEN
SET v_MONTHS = v_MONTHS + ((v_ENDMONTH - v_STARTMONTH)-1);
END IF;
END IF;
END IF;
IF v_YEARS<10 THEN
SET v_Year=CONCAT('0', v_YEARS);
ELSE
SET v_Year= v_YEARS;
END IF;
IF v_MONTHS<10 THEN
SET v_Month= CONCAT('0', v_MONTHS);
ELSE
SET v_Month= v_MONTHS;
END IF;
IF v_DAYS<10 THEN
SET v_Day= CONCAT('0',v_DAYS);
ELSE
SET v_Day= v_DAYS;
END IF;
SET v_TempValue = CONCAT(v_Year, '-', v_Month, '-', v_Day);
RETURN v_TempValue;
END;
This is the simplest I could come up with so far:
SELECT FLOOR(ABS(DATEDIFF(d, CURRENT_TIMESTAMP, dob))/365.25) AS age
First we get the date difference in days, then convert it to years, then FLOOR truncates to the integer part of the number.
Depends on your needs
- int and float functions provided.
- Your business rules may differ so adjust accordingly
DROP FUNCTION IF EXISTS `age`;
CREATE FUNCTION `age` (
`pdate_begin` DATE,
`pdate_end` DATETIME
) RETURNS INT(11) UNSIGNED
COMMENT 'Calc age between two dates as INT'
DETERMINISTIC NO SQL SQL SECURITY DEFINER
RETURN floor(datediff(pdate_end, pdate_begin) / 365.25) ;
DROP FUNCTION IF EXISTS `age_strict`;
CREATE FUNCTION `age_strict` (
`pdate_begin` DATE,
`pdate_end` DATETIME
) RETURNS decimal(10,4)
COMMENT 'Calc age between two dates as DECIMAL .4'
DETERMINISTIC NO SQL SQL SECURITY DEFINER
RETURN round(datediff(pdate_end, pdate_begin) / 365.25, 4) ;
-- test harness
select
age(dob, now()) as age_int,
age_strict(dob, now()) as age_dec
from customer
where dob is not null
order by age(dob,now()) desc;
-- test results
dob, age_int, age_dec
1981-01-01 00:00:00 33 33.9713
1987-01-09 00:00:00 27 27.9507
2014-11-25 00:00:00 0 0.0739
DELIMITER $$ DROP FUNCTION IF EXISTS `test`.`__AGE` $$
CREATE FUNCTION `_AGE`(in_dob datetime) RETURNS VARCHAR(100)
NO SQL
BEGIN
DECLARE l_age VARCHAR(100);
DECLARE YEARS INT(11);
DECLARE MONTHS INT(11);
DECLARE DAYS INT(11);
DECLARE DIFFS FLOAT;
SET DIFFS=DATEDIFF(CURRENT_DATE(),in_dob) /365.25;
SET YEARS=FLOOR(DIFFS) ;
SET MONTHS=FLOOR((DIFFS - YEARS)*365.25/30.4375) MOD 12;
SET DIFFS=((DIFFS - YEARS)*365.25/30.4375);
SET DAYS=CEIL(((DIFFS-MONTHS)*30.4375)) MOD 31;
RETURN(CONCAT(YEARS, " Year ",MONTHS," Month ",DAYS," Days"));
END $$
DELIMITER ;
SELECT __Age(CAST('1980-07-16' AS DATE));
Assumed the given date is greater than the current date,
1.Find the total no of days b/w the current date and the given date.
-> DATEDIFF(NOW(),'1988-05-01')
2.Find the no of years from the calculated no of days.
-> DATEDIFF(NOW(),'1988-05-01')/365.25
3.The age should be the completed no of years by a person. To get it, we can use 'floor' to the calculated no of years.
-> FLOOR(DATEDIFF(NOW(),'1988-05-01')/365.25)
Example: SELECT FLOOR(DATEDIFF(NOW(),'1988-05-01')/365.25) AS age;