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
;
Related
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 a problem that I tried googling but most questions are about rounding down hours or minutes.
I'm checking birthday dates for users and I have two dates that are 99.3 years apart. That means that the user is 99 years old but this piece of code:
DATEDIFF(YEAR, r.BirthDate, ISNULL(#Date,GETDATE()))
returns a value of 100. Is there a way to round the value down?
You can use this logic to get the correct age:
select (case when month(birthdate) * 100 + day(birthdate) >=
month(getdate()) * 100 + day(getdate())
then year(getdate()) - year(birthdate)
else year(getdate()) - year(birthdate) - 1
end) as age
This should be accurate, even in the presence of leap years. Basically it looks at the month-day portion of the birthdate and checks if it is on or later than today. The logic uses this information to determine the age in year.
fin the difference in whole years (year - birth year) This is always the age the person reaches in that year. Knock a year off if it is earlier than their birthday.
Never be tempted to use day difference divided by 365.25 or 365 - for all sorts of reasons, the age can end up coming out wrong at certain dates, sometimes around leap-years
SELECT YEAR(getdate()) - YEAR(birthdate)
- CASE WHEN MONTH(getdate()) < MONTH(birthdate)
OR (DAY(getdate()) < DAY(birthdate) AND MONTH(getdate()) = MONTH(birthdate) )
THEN
1
ELSE
0
END
This is how fixed it.
Instead of:
DATEDIFF(YEAR, r.BirthDate, ISNULL(#Date,GETDATE()))
use this:
FLOOR(DATEDIFF(week, r.BirthDate, ISNULL(#Date,GETDATE())) / 52.177457)
Here's an article that demonstrates that this trick works like a charm.
You can use the following solution using MONTH instead of YEAR:
DECLARE #currdate AS DATE = '2019-02-08'
-- using YEAR
SELECT DATEDIFF(YEAR, '2000-05-01', ISNULL(#currdate, GETDATE())) -- 19
-- using MONTH
SELECT DATEDIFF(MONTH, '2000-05-01', ISNULL(#currdate, GETDATE())) / 12 -- 18
You can also ROUND up and down:
DECLARE #date DATE = '2019-02-08'
SELECT CAST(ROUND(DATEDIFF(MONTH, '1999-08-01', ISNULL(#date, GETDATE())) / 12.0, 0) AS INT)
-- 20 (19.5)
SELECT CAST(ROUND(DATEDIFF(MONTH, '1999-09-01', ISNULL(#date, GETDATE())) / 12.0, 0) AS INT)
-- 19 (19.4)
is there a way to round down days?
You can use days to round for days but this isn't more precise in some cases. You can check if the current date passed the day of birth or not (as #Cato mentioned in comments). In case the day of birth is greater than the current day (in same month) you can subtract a month.
DECLARE #birthday AS DATE = '2000-10-25'
DECLARE #currdate AS DATE = '2100-10-24'
SELECT ((DATEDIFF(MONTH, #birthday, ISNULL(#currdate, GETDATE())) - (CASE WHEN MONTH(#birthday) = MONTH(#currdate) AND DAY(#birthday) > DAY(#currdate) THEN 1 ELSE 0 END)) / 12)
-- 99
The accepted solution by Gordon is good but the logic is reversed? The general idea is to see if the current month + day is greater than the birthdate's month + day and, if not, then subtract a year from the difference in years, because it hasn't reached or surpassed their birthdate yet.
SELECT YEAR(GETDATE()) - YEAR(birthdate)
- IIF(MONTH(GETDATE()) * 100 + DAY(GETDATE()) >= MONTH(birthdate) * 100 + DAY(birthdate), 0, 1)
Another way to solve this (without calculating the date difference 3 times or more) is to get the total number of years when subtracting the two values:
SELECT datediff(YEAR, '1900', DATEADD(d, -1, GETDATE()) - r.BirthDate)
we subtract 1 day from the current date as the other day is '1/1/1900', which adds one day to the interval.
In Snowflake:
ROUND(DATEDIFF('month', "dateOfBirth", CURRENT_DATE())/12)
You have to do it by months as if you pick years it seems to round up.
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.
So far I have:
Select FullName, DateOfBirth, CountryOfBirth
FROM Students
WHERE Gender = F
however I want the DateOfBirth to be Displayed as an age under an age heading.
Can I use this: (Datediff("yyyy",DateOfBirth,DATE())) if so where in my original statement would it go?
Select FullName, DATEDIFF(year,DateOfBirth,DATE()) , CountryOfBirth FROM Students WHERE Gender = F
You can modify the DATEDIFF function to calculate the age according to the date instead of just the year
You probably don't want to use datediff with yyyy as that won't actually give you the ages correctly. It'll give you the years since the year they were born. If someone has a birthday later in the year than today then they'll be returned as a year older than they are.
What I would do is use datediff with hour or day:
datediff(day, DateOfBirth, DATE()) / 365
or
datediff(hour, DateOfBirth, DATE()) / (24 * 365)
You need a proper method for calculating age - an example is shown here:
https://stackoverflow.com/a/29127001/3527297
Yes, you can use the DateDiff function to achieve this. That function would replace the DateOfBirth column in the query, to become:
SELECT FullName, DATEDIFF(yyyy, DateOfBirth, DATE()) As Age, CountryOfBirth
FROM Students
WHERE Gender = F
Unfortunately, there is some contention around leap years in SQL. There isn't a straightforward way to deal with them. There's an updated statement below, but it awkwardly uses cases:
DECLARE #startDate DATETIME = '1984-01-02'
DECLARE #endDate DATETIME = '2015-01-01'
Select Case
When DatePart ( day, #startDate) <= DatePart (day , #endDate )
Then DateDiff ( year, #startDate, #endDate)
When DateDiff (year , #startDate , DateAdd (year , - 1, #endDate)) = - 1
Then 0
Else DateDiff (year , #startDate , DateAdd (year , - 1, #endDate))
End As DoB
You may want to consider putting this DateOfBirth check into a Function for brevity/re-usability.
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