I want to convert the DOB into the number age, then assign the age value into different age groups on SQL Server.
I have found the way to do the first step, and the second step ideally I should set the first step's result as a variable and let it compare in the CASE statement. However, I don't know declare and set the variable and use it in CASE.
I got the table I want with a silly way as below:
SELECT FirstName, LastName,
CAST(
CASE
WHEN FLOOR((CAST (GetDate() AS INTEGER) - CAST(dob AS INTEGER)) / 365.25) < 18
THEN 'Under 18'
WHEN FLOOR((CAST (GetDate() AS INTEGER) - CAST(dob AS INTEGER)) / 365.25) BETWEEN 19 AND 30
THEN '19-30'
WHEN FLOOR((CAST (GetDate() AS INTEGER) - CAST(dob AS INTEGER)) / 365.25) > 30
THEN 'Over 30'
ELSE 'ERROR'
END AS VARCHAR(10)) AS Age
FROM Student
MY QUESTION: Is there a way to set "FLOOR((CAST (GetDate() AS INTEGER) - CAST(DOB AS INTEGER)) / 365.25)" as a variable and use it in the CASE statement?
*FirstName, LastName and dbo are columns in Student Table.
Thank you!
No, not in the case statement. The two traditional recommendations are to use CTEs or subqueries. But, SQL Server also supports apply:
SELECT FirstName, LastName,
(CASE WHEN v.age <= 18 THEN 'Under 18'
WHEN v.age <= 30 THEN '19-30'
WHEN v.age > 30 THEN 'Over 30'
ELSE 'ERROR'
END) AS Age
FROM Student s OUTER APPLY
(VALUES (FLOOR((CAST (GetDate() AS INTEGER) - CAST(dob AS INTEGER)) / 365.25) )
) as v(age);
Comments:
You don't need to cast strings to varchar(10). That is just superfluous.
The case is evaluated in order, so you don't need between. This makes it much easier if you want to change the boundaries.
Related
I'm having a SELECT statement as follow (doesn't work):
SELECT foo,
extract(day from CAST (date as TIMESTAMP) - CAST (birth_date as TIMESTAMP)) / 365.25 as age_norm,
CASE
WHEN age_norm >= 0 AND age_norm <1 THEN '00'
WHEN age_norm >= 1 AND age_norm <5 THEN '01-4'
--etc
END as age_group
FROM bar
Is there a way to "inject" here the "variable" age_normin the query ?
NOTE
Asked a similar question here, but without the parameter foopresent in this question
EDIT
Tried:
SELECT foo,
(
SELECT t.age_norm,
CASE
WHEN t.age_norm >= 0 AND t.age_norm <1 THEN '00'
WHEN t.age_norm >= 1 AND t.age_norm <5 THEN '01-4'
--etc
END
FROM (SELECT extract(day from CAST (date as TIMESTAMP) - CAST (birth_date as TIMESTAMP)) / 365.25 as age_norm FROM bar) t
)
as age_group
FROM bar
But getting:
ERROR: subquery must return only one column
LINE 10: ( SELECT t.age_norm,
^
SQL state: 42601
Character: 212
CONCLUSION
Tried some of proposed solutions but either the resulting query is too slow (compared to hard coding the extract function in each where clause) or the resulting query become too complicate (it is in fact more complicate than expressed in this post with group by clauses and others things).
So will implements each when clause as follow:
WHEN (extract(day from CAST (date as TIMESTAMP) - CAST (birth_date as TIMESTAMP)) / 365.25) >=0 AND (extract(day from CAST (date as TIMESTAMP) - CAST (birth_date as TIMESTAMP)) / 365.25) <1 THEN '00'
etc.
Thank you for your replies!
Use a derived table (a query in the FROM clause):
SELECT
foo,
age_norm,
CASE
WHEN age_norm >= 0 AND age_norm <1 THEN '00'
WHEN age_norm >= 1 AND age_norm <5 THEN '01-4'
END as age_group
FROM (
SELECT
foo,
extract(day from CAST (date as TIMESTAMP) - CAST (birth_date as TIMESTAMP)) / 365.25 as age_norm
FROM bar
) s
perhaps a lateral join like this....
SELECT foo,age_group.*
FROM
FROM bar
, LATERAL (
SELECT t.age_norm,
CASE
WHEN t.age_norm >= 0 AND t.age_norm <1 THEN '00'
WHEN t.age_norm >= 1 AND t.age_norm <5 THEN '01-4'
--etc
END
FROM (SELECT extract(day from CAST (bar.date as TIMESTAMP) - CAST bar.birth_date as TIMESTAMP)) / 365.25 as age_norm ) t
) as age_group;
In the users table I have birth_date column. I want to select only users under the age 18.
I tried using alias
select
*,
age = case
when datediff(year, getdate(), birth_date) > 0
then year(getdate()) - year(birth_date) - 1
else year(getdate()) - year(birth_date)
end
from
users
where
age < 18
But apparently I cannot use alias in where.
So I tried using case but it's also not gonna work
select *
from users
where
case
when datediff(year, getdate(), birth_date) > 0
then year(getdate()) - year(birth_date) - 1 < 18
else year(getdate()) - year(birth_date) < 18
What shall I do in this case? I don't want to use a stored procedure.
Use cte
WITH cte AS
(
SELECT *,
CASE
WHEN DATEDIFF(year, getdate(), birth_date) > 0
THEN year(getdate()) - year(birth_date) - 1
ELSE year(getdate()) - year(birth_date)
END AS age
FROM users
)
SELECT *
FROM cte
WHERE age < 18
demo in db<>fiddle
The correct way to do this is not to use DATEDIFF at all. It will be less accurate (as it uses date boundaries) and slower (it can't use indexes).
Instead use DATEADD against the current date, do not use functions against the column
SELECT *
FROM dbo.users
WHERE birth_date > DATEADD(year, -18, GETUTCDATE()) -- maybe cast right-side to DATE?
db<>fiddle
simple use this !
SELECT * FROM dbo.users WHERE DATEDIFF(day,birth_date,GETDATE()) < 6570
I think you're just looking for direction on how to use an alias/CASE statement in a column?
If that's correct, then you'll just need to surround your alias with brackets.
select *
,case
when datediff(year, getdate(), birth_date) > 0
then year(getdate()) - year(birth_date) - 1
else year(getdate()) - year(birth_date)
end as age
from users
where age < 18
Below is one way to calculate age which accounts for leap days and other complexities. This calculates the difference of the yyyymmdd integer values and then divides by 10000 to evaluate only the year difference.
SELECT *
FROM users
WHERE
(CAST(FORMAT(GETDATE(), 'yyyyMMdd') AS int) -
CAST(FORMAT(birth_date, 'yyyyMMdd') AS int)) / 10000 < 18;
I have following task:
Show the list of first, last names and ages of the employees whose age
is greater than 55. The result should be sorted by last name.
This is my code:
SELECT
LastName, FirstName,
(CASE
WHEN (CONVERT(INT, GETDATE()) - CONVERT(INT, BirthDate)) > 55
THEN CONVERT(INT, GETDATE()) - CONVERT(INT, BirthDate)
END) as Age
FROM
Employees
ORDER BY
LastName
This is what I get:
This is the BirthDate table (datetime):
Why does the age go so crazy? What's wrong?
For age, use expression
DateDiff(year, birthdate, getdate()) +
case when Month(getdate()) > Month(birthdate)
or Day(getdate()) >= Day(birthdate)
then 1 else 0 end
i.e.,
SELECT LastName, FirstName,
DateDiff(year, birthdate, getdate()) +
case when Month(getdate()) > Month(birthdate)
or Day(getdate()) >= Day(birthdate)
then 1 else 0 end Age
FROM Employees
where DateDiff(year, birthdate, getdate()) +
case when Month(getdate()) > Month(birthdate)
or Day(getdate()) >= Day(birthdate)
then 1 else 0 end > 55
ORDER BY LastName
SELECT *
FROM
(SELECT
LastName, FirstName,
(CASE
WHEN DATEDIFF(yy, BirthDate, GETDATE()) > 55
THEN DATEDIFF(yy, BirthDate, GETDATE())
ELSE 0
END) AS Age
FROM
Employees) AS ABC
WHERE
ABC.Age != 0
ORDER BY
ABC.LastName
Problem in your result is you are converting Date to int and you didn't convert the Int back to Date
Add the filter in Where clause. To calculate age I always use below method
SELECT FLOOR(DATEDIFF(DAY, '1990-07-20', getdate()) / 365.25)
Result : 26
SELECT LastName,
FirstName,
Floor(Datediff(DAY, BirthDate, Getdate()) / 365.25) AS Age
FROM Employees
WHERE Floor(Datediff(DAY, BirthDate, Getdate()) / 365.25) > 55
ORDER BY LastName
I strongly advise you to not use datediff(). It does not work intuitively. It counts the number of year boundaries between two dates. Although there is a relationship between New Year's celebrations and age, the two are not equivalent.
Instead:
SELECT LastName, FirstName
FROM Employees
WHERE birthdate < DATEADD(year, -55, getdate())
ORDER BY LastName;
Unfortunately, that doesn't get the age. That is a bit tricky. You could use datediff() just to be "close enough". The exactly logic is a bit of a pain. I would refer you here.
I have a scenario in which I have to get those users whose age is between say (10 - 20) in sql, I have a column with date of birth dob. By executing the below query I get the age of all users.
SELECT
FLOOR((CAST (GetDate() AS INTEGER) - CAST(dob AS INTEGER)) / 365.25) AS Age
FROM users
My question is how should I write my query so that I can get that users whose age is between 10 to 20
I don't have a SQL-Server available to test right now. I'd try something like:
select * from users where datediff(year, dob, getdate()) between 10 and 20;
First add computed field Age like you already did. Then make where filtering on the data.
SELECT * FROM
(SELECT FLOOR((CAST (GetDate() AS INTEGER) - CAST(dob AS INTEGER)) / 365.25) AS Age, *
from users) as users
WHERE Age >= 10 AND Age < 20
There are number of ways to calculate age.
You can try the following:
SELECT * FROM TableName
WHERE DATEDIFF(year, dob, getdate()) between #dob and #currentDate;
OR
SELECT DATEDIFF(day,'2014-06-05','2014-08-05') AS DiffDate;
Reference: http://www.w3schools.com/sql/func_datediff.asp
OR
http://sqlhints.com/2015/07/10/how-to-get-difference-between-two-dates-in-years-months-and-days-in-sql-server/
Below query should return the users :
SELECT *
from users
where FLOOR ( (CAST (GetDate() AS INTEGER) - CAST(dob AS INTEGER)) / 365.25)
between 10 and 20;
Instead of calculating each users age you might simply change your WHERE-condition to:
where dob between cast(dateadd(year, 20, getdate()) as date)
and cast(dateadd(year, 10, getdate()) as date)
Now it's a sargable expression and might use an index.
I found this question trying to figure out something very similar. I'm really new to SQL and found a discussion about calculating age from date of birth here.
I've adapted one of the answers there into this: I think it works.
SELECT
(0 + Convert(Char(8),GETDATE(),112) - Convert(Char(8),dob,112)) / 10000 AS Age
FROM
users
WHERE
(0 + Convert(Char(8),GETDATE(),112) - Convert(Char(8),dob,112)) / 10000 BETWEEN 10 and 20
;
How to select people within age limit 19 t0 25 if the current date is less than '2011-01-01'
and age limit between 19 to 26 if the current date is greater than or equal to'2011-01-01'
You can use simple AND-OR logic to acheive this.
Select * from <people_table>
where ( (age between 19 and 25) and
(current_date < to_date('2011-01-01','YYYY-MM-DD'))
)
or ( (age between 19 and 26) and
(current_date >= to_date('2011-01-01','YYYY-MM-DD'))
)
Unless of course, by current_date, if you mean sysdate, you'll have...
Select * from <people_table>
where ( (age between 19 and 25) and
(sysdate < to_date('2011-01-01','YYYY-MM-DD'))
)
or ( (age between 19 and 26) and
(sysdate >= to_date('2011-01-01','YYYY-MM-DD'))
)
Well, in MySQL, CURDATE() will get you the current date.
Then, you could sue DATEDIFF() and see if the difference is in a range you want.
For example,
SELECT *
FROM table
WHERE DATEDIFF(year,CURDATE(),date) > 18 AND DATEDIFF(year, CURDATE(), date) < 26;
Try this -
select * from people_table
where age > 19 and age <=
case
when (getdate() < '2011-01-01') then 25
when (getdate() >= '2011-01-01') then 26
end