I have written a query, and from the date of birth field, and I working out the age of a person and then using AS age to create an age field.
My question is, is it possible to the match again that age field?
Something like this,
SELECT `candidates`.`candidate_id`,
`candidates`.`first_name`,
`candidates`.`surname`,
`candidates`.`DOB`,
`candidates`.`gender`,
DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(`candidates`.`DOB`, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(`candidates`.`DOB`, '00-%m-%d')) AS `age`
FROM `candidates`
WHERE `age` <= 20
Any help would be greatly appreciated?
-----So I have changed WHERE to HAVING and here is my full query------
SELECT `candidates`.`candidate_id`,
`candidates`.`first_name`,
`candidates`.`surname`,
`candidates`.`DOB`,
`candidates`.`gender`,
`candidates`.`talent`,
`candidates`.`location`,
`candidates`.`availability`,
`candidate_assets`.`url`,
`candidate_assets`.`asset_size`
FROM `candidates`
LEFT JOIN `candidate_assets` ON `candidate_assets`.`candidates_candidate_id` = `C`.`candidate_id`
WHERE `C`.`availability` = 'yes'
AND C.talent = "actor"
AND C.skill = "accents"
AND C.gender = "male"
AND HAVING DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(`candidates`.`DOB`, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(`candidates`.`DOB`, '00-%m-%d')) <= 69
AND HAVING DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(`candidates`.`DOB`, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(`candidates`.`DOB`, '00-%m-%d')) <=19
AND HAVING DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(`candidates`.`DOB`, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(`candidates`.`DOB`, '00-%m-%d')) <=49
I get the following error,
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 'HAVING DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(candidates.DOB, '%Y') - (DATE_' at line 15
For the life of me I have no idea what it is.
One way to do this is to wrap the original query as a subquery, and move the WHERE clause to the outer query:
SELECT * FROM (
SELECT `candidates`.`candidate_id`, -- this is the original query
`candidates`.`first_name`,
`candidates`.`surname`,
`candidates`.`DOB`,
`candidates`.`gender`,
DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(`candidates`.`DOB`, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(`candidates`.`DOB`, '00-%m-%d')) AS `age`
FROM `candidates` ) as innertable
WHERE `age` <= 20 -- this is now part of the outer query
clarification: this DOES work in MySQL 5
note: this assumes that the original query works
You could try replacing the WHERE clause with HAVING. MySQL won't be able to use indexes to optimize the result set if you do that, though.
No
Aliased fields can, however, be used in the ORDER clause as well as others. But not WHERE.
I know you can do this in SQL Server, but not sure if you can in MySQL.
select * from
(SELECT `candidates`.`candidate_id`,
`candidates`.`first_name`,
`candidates`.`surname`,
`candidates`.`DOB`,
`candidates`.`gender`,
DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(`candidates`.`DOB`, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(`candidates`.`DOB`, '00-%m-%d')) AS `age`
FROM `candidates`) as newTable
WHERE `age` <= 20
Hope it helps.
To address the problem you're having converting to HAVING:
HAVING is a clause, similar to WHERE, but applied after the result is constructed. If you go back to your first query, it would look something like this (borrowing the WHERE from your second query to make it more clear):
SELECT `candidates`.`candidate_id`,
`candidates`.`first_name`,
`candidates`.`surname`,
`candidates`.`DOB`,
`candidates`.`gender`,
DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(`candidates`.`DOB`, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(`candidates`.`DOB`, '00-%m-%d')) AS `age`
FROM `candidates`
WHERE `C`.`availability` = 'yes'
AND C.talent = "actor"
AND C.skill = "accents"
AND C.gender = "male"
HAVING `age` <= 20
Related
I'm doing the reports for my project. And I want to get the range of age of all the beneficiary. I did it but the problem is the age range is on the column. I want to put it on the row. Can somebody help me with my problem?
SELECT
SUM(IF(DATE_FORMAT(NOW(), '%Y') -
DATE_FORMAT(birth_date, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') <
DATE_FORMAT(birth_date, '00-%m-%d')) BETWEEN 18 and 24,1,0)) as '18 - 24',
SUM(IF(DATE_FORMAT(NOW(), '%Y') -
DATE_FORMAT(birth_date, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') <
DATE_FORMAT(birth_date, '00-%m-%d')) BETWEEN 25 and 34,1,0)) as '25 - 34',
SUM(IF(DATE_FORMAT(NOW(), '%Y') -
DATE_FORMAT(birth_date, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') <
DATE_FORMAT(birth_date, '00-%m-%d')) BETWEEN 35 and 44,1,0)) as '35 - 44'
FROM tbl_beneficiary
This is the output of the query above
Output
18-24 25-34 35-44 ...
1 0 0
I want this to be the result
Age Total
18-24 1
25-34 0
35-44 0
...
Since you're interested in zero counts as well, you could build (or generate) a table of range brackets and LEFT JOIN with it. Rough outline of query (does not use the correct method of age calculation):
SELECT brackets.lbl, COUNT(t.id)
FROM (
SELECT 0 AS a, 17 AS b, '<18' AS lbl UNION ALL
SELECT 18, 24, '18-24' UNION ALL
SELECT 25, 34, '25-34' UNION ALL
SELECT 35, 44, '35-44' UNION ALL
SELECT 45, 999, '45+'
) AS brackets
LEFT JOIN t ON YEAR(CURRENT_DATE) - YEAR(birth_date) BETWEEN a and b
GROUP BY brackets.lbl
Use a case expression:
select (case when birthdate > now() - interval 18 year then 'Under 18'
when birthdate > now() - interval 25 year then '18 - 24'
when birthdate > now() - interval 35 year then '25 - 34'
. . .
end) as age_group,
count(*)
from t
group by age_group
order by birthdate;
I have a user table with the user's birthday (YYYY-MM-DD) as well as age. I want to run a script to calculate and update the age column nightly via cron.
This SQL works well for selecting and calculating the age:
SELECT
DATE_FORMAT(NOW(), '%Y') -
DATE_FORMAT(`birthday`, '%Y') -
(DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(`birthday`, '00-%m-%d')) AS age
FROM
`jos_jcourse_students`
But is it possible to update the age column with a single statement? Tried the following, but all I managed to do was populate the age column with all 0s! Do I need to use some sort of MySQL loop?
UPDATE
`jos_jcourse_students`
SET
age = "SELECT DATE_FORMAT(NOW(), '%Y') -
DATE_FORMAT(`birthday`, '%Y') -
(DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(`birthday`, '00-%m-%d')) AS age
FROM
`jos_jcourse_students`"
UPDATE `jos_jcourse_students`
SET age = DATE_FORMAT(FROM_DAYS(TO_DAYS(NOW())-TO_DAYS(birthday)), '%Y')+0
OR according to your logic it will be
UPDATE `jos_jcourse_students`
SET age =((DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(`birthday`, '%Y')) -
(DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(`birthday`, '00-%m-%d')))
UPDATE
`jos_jcourse_students`
SET
age = (SELECT DATE_FORMAT(NOW(), '%Y') -
DATE_FORMAT(`birthday`, '%Y') -
(DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(`birthday`, '00-%m-%d')) AS age
FROM
`jos_jcourse_students`)
One way you can achieve the above result by using the self join technique. i.e join to the same table using its unique id (primary key example studentId)
UPDATE jos_jcourse_students a,
( SELECT studentId, DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(`birthday`, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(`birthday`, '00-%m-%d')) AS age
FROM `jos_jcourse_students`) b
SET a.age = b.age
WHERE a.studentId = b.studentId
Note: studentId is primary key in jos_jcourse_students
What I am trying to do is have a field called 'age' autopopulate from a persons date of birth when a row is added - the trick is the persons date of birth resides in anouther field.
My two tables are:
student
student_id (PK), first_name, last_name, date_of_birth
fitness_report
report_id (PK), test_date, test_period, age_tested, student_id (FK)
ideally the age_tested will be caluclated from the test_period however happy to use ()NOW as that'll be within reasonable limits.
Obviously what i need to do here is create a trigger - but not sure on the SELECT statement to get the age to populate. Help is much appreciated.
As rwilliams said, it is not advisable to store the age_tested as it is redundant but if it is what you want to do you can wrap a simple trigger around Mosty's solution -
CREATE TRIGGER fitness_report_insert BEFORE INSERT ON `fitness_report`
FOR EACH ROW
BEGIN
SET NEW.age_tested = (SELECT DATE_FORMAT(NEW.test_period, '%Y') - DATE_FORMAT(student.date_of_birth, '%Y') - (DATE_FORMAT(NEW.test_period, '00-%m-%d') < DATE_FORMAT(student.date_of_birth, '00-%m-%d')) FROM student WHERE student.student_id = NEW.student_id);
END
This assumes that test_period is a date as previously mentioned by Mosty. I have not tried this as I do not have access to a server right now so it may need a little tweaking.
UPDATE: You could try the following as a starting point for your stats -
SELECT
DATE_FORMAT(test_period, '%Y') - DATE_FORMAT(date_of_birth, '%Y') - (DATE_FORMAT(test_period, '00-%m-%d') < DATE_FORMAT(date_of_birth, '00-%m-%d')) AS age,
s.gender,
AVG(r.score) AS score
FROM student s
INNER JOIN fitness_report r
ON s.student_id = r.student_id
GROUP BY age, s.gender
This is how to get current age:
select s.name, s.date_of_birth,
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 s
Example
This is how to get age up to the test_period (shouldn't it be test_date?):
select s.name, s.date_of_birth, r.test_period,
date_format(test_period, '%Y') - date_format(date_of_birth, '%Y') -
(date_format(test_period, '00-%m-%d') < date_format(date_of_birth, '00-%m-%d'))
as age
from r
join s on s.id_student = r.student_id
Example
I have the following query,
SELECT `candidates`.`candidate_id`,
`candidates`.`first_name`,
`candidates`.`surname`,
`candidates`.`DOB`,
`candidates`.`gender`,
`candidates`.`talent`,
`candidates`.`location`,
`candidates`.`availability`,
DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(`candidates`.`DOB`, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(`candidates`.`DOB`, '00-%m-%d')) as `age`,
`candidate_assets`.`url`,
`candidate_assets`.`asset_size`
FROM `candidates`
LEFT JOIN `candidate_assets` ON `candidate_assets`.`candidates_candidate_id` = `candidates`.`candidate_id`
WHERE `candidates`.`availability` = 'yes'";
The query is currently returning multiple rows from the joined table is possible to return only one result per join?
It is possible. Try to use GROUP_CONCAT function, e.g. -
SELECT
c.`candidate_id`,
c.`first_name`,
c.`surname`,
c.`DOB`,
c.`gender`,
c.`talent`,
c.`location`,
c.`availability`,
DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(c.`DOB`, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(c.`DOB`, '00-%m-%d')) as `age`,
GROUP_CONCAT(ca.`url`) `url`,
GROUP_CONCAT(ca.`asset_size`) `asset_size`
FROM `candidates` c
LEFT JOIN `candidate_assets` ca ON ca.`candidates_candidate_id` = c.`candidate_id`
WHERE c.`availability` = 'yes'
GROUP BY c.candidate_id
The title explains my whole question. Here's the query:
select
date_format(now(), '%Y') - date_format(date_of_birth, '%Y') age,
IF(date_format(now(), '%Y') - date_format(date_of_birth, '%Y') < 18,
'Under 18',
IF(date_format(now(), '%Y') - date_format(date_of_birth, '%Y') <= 24,
'19 to 24',
IF(date_format(now(), '%Y') - date_format(date_of_birth, '%Y') <= 34,
'25 to 34',
'Over 34'))) age_range
from customer
I suggest a combination of case and a nested query - something like:
select s.age,
case when s.age < 18 then 'Under 18'
when s.age <= 24 then '19 to 24'
when s.age <= 34 then '25 to 34'
else 'Over 34'
end case as age_range
from (select date_format(now(), '%Y') - date_format(date_of_birth, '%Y') as age
from customer) s
Looks like a good match for CASE.
Is should look something like the following (untested):
select
date_format(now(), '%Y') - date_format(date_of_birth, '%Y') age,
CASE age
WHEN age < 18 THEN 'Under 18'
WHEN age <= 24 THEN '19 - 24'
WHEN age <= 34 THEN '25 - 34'
ELSE 'Over 34'
END CASE AS age_range
from customer