How to Determine the Age of a Person in aTable [duplicate] - mysql

This question already has answers here:
Calculate age in MySQL (InnoDB)
(13 answers)
Closed 8 years ago.
I am trying to determine the age of the people that are listed in my database. This is what I came up with, but I can't seem to limit the query to show people who are only 18 and under.
SELECT
*
FROM
patientdetails
WHERE
ageInYears IN (
SELECT
DATEDIFF(CURRENT_DATE, STR_TO_DATE(p.DOB, '%d-%m-%Y'))/365 AS ageInYears
FROM
patientdetails p
) < 19

I believe something like this should work:
SELECT *
FROM patientdetails
WHERE DATEDIFF(CURRENT_DATE, STR_TO_DATE(p.DOB, '%d-%m-%Y'))/365 < 19

You don't need the subquery:
SELECT *
FROM PatientDetails pd
WHERE DATEDIFF(CURRENT_DATE, STR_TO_DATE(p.DOB, '%d-%m-%Y'))/365 <19

This sort of works:
SELECT *
FROM PatientDetails pd
WHERE DATEDIFF(CURRENT_DATE, STR_TO_DATE(pd.DOB, '%d-%m-%Y')) / 365 < 19
Dividing the days by 365 will fail to accommodate for leap years, meaning you will be off by 4 days guaranteed. You could divide by 365.25 and then subtract 0.75. I think that accounts for everything, but I'm shooting from the hip a bit. I'm not sure offhand if there would be integer errors with this calculation or not. I'm not sure how MySQL handles implicit typecasting.
I would be more inclined to do it this way. Logically, it's "all patients whose 19th birthday is in the future":
SELECT *
FROM PatientDetails pd
WHERE DATE_ADD( STR_TO_DATE(pd.DOB, '%d-%m-%Y'), INTERVAL 19 YEAR ) > CURDATE()
However, this exact question is addressed and explained in the MySQL documentation for date calculations, but it seems kind of ass-backwards to me:
SELECT name, birth, CURDATE(),
(YEAR(CURDATE())-YEAR(birth))
- (RIGHT(CURDATE(),5)<RIGHT(birth,5))
AS age
FROM pet

Related

Only count working days in a DATEDIFF (MySQL)

So, next problem :'), I have the following query that #MatBailie provided to me here (thanks again!):
SELECT
taskname,
employee,
SUM(
DATEDIFF(
LEAST( enddate, '2023-12-31'),
GREATEST(startdate, '2023-01-01')
)
+1
) AS total_days,
FROM
schedule
WHERE
startDate <= '2023-12-31'
AND
endDate >= '2023-01-01'
GROUP BY
employee,
taskname
This query will tell me how many days a certain employee has spent on a certain task in a given period of time, and it works great!
The next thing I would like to do however, is to substract non-working days from the SUM of DATEDIFFs for some of the tasks (e.g. when the task has "count_non_working_days= 0" in a reference table called 'activities').
For example, my schedule also keeps track of the amount of days off every employee has taken (days off are also scheduled as tasks). But of course, days off that fall in a weekend or on a holiday should not be counted towards the total of days off a person has taken in a year. (Note that I did consider scheduling days off only on weekdays/non-holidays, but this is not a practical option in the scheduling software I use because employees request a leave from date A to date B, and this request is approved or denied as-is (they don't make 3 holiday requests excluding the weekends if they want to go on a vacation for 3 weeks, if you get my drift).
So, if an employee goes on a vacation for 10 days, this is counted as 10 days off, but this holiday may have 1 or 2 weekends in it, so the sum of days of that the employee has taken off should be 6, 7 or 8, and not 10. Furthermore, if it has a holiday such as Easter Monday in it (I have all dates of my holidays in a PHP array), this should also be subtracted.
I have tried the solutions mentioned here, but I couldn't get them to work (a) because those are in SQL server and (b) because they don't allow putting in an array of holidays, (c) nor allow toggling the subtraction on and off depending on the event type.
Here's my attempt of explaining what I'm trying to do in my pseudo-SQL:
SELECT
taskname,
employee,
IF( activities.count_non_working_days=1,
-- Just count the days that fall in the current year:
SUM(
DATEDIFF(
LEAST( enddate, '2023-12-31'),
GREATEST( startdate, '2023-01-01')
)
+ 1
) AS total_days,
-- Subtract the amount of saturdays, sundays and holidays:
SUM(
DATEDIFF(
LEAST( enddate, '2023-12-31'),
GREATEST( startdate, '2023-01-01')
)
- [some way of getting the amount of saturdays, sundays and holidays that fall within this date range]
+ 1
) AS total_days
)
FROM
schedule
LEFT JOIN
activities
ON activity.name = schedule.name
WHERE
startDate <= '2023-12-31'
AND
endDate >= '2023-01-01'
GROUP BY
employee,
taskname
I know the query above is probably faulty on so many levels, but I hope it clarifies what I'm trying to do.
Thanks once more for all the help!
Edit: basically I need something like this, but in MySQL and preferably with a toggle that turns the subtraction on or off depending on the task type.
Edit 2: To clarify: my schedule table holds ALL activities, including holidays. For example, some records may include:
employee
taskname
startDate
endDate
Mr. Anderson
Programming
2023-01-02
2023-01-06
Mr. Anderson
Programming
2023-01-09
2023-01-14
Mr. Anderson
Vacation
2023-01-14
2023-01-31
In another table, Programming is defined as "count_non_working_days=1", because working in the weekends should count, while Vacation is defined as "count_non_working_days=0", because taking a day off on the weekend should not count towards your total amount of days taken off.
The totals for this month should therefore state that:
Mr. Anderson has done Programming for 11 days (of which 1 was on a saturday)
Mr. Anderson has taken 12 days off for (because the 2 weekends in this period don't count as days off).
Create a calendar table, with every date of interest (so, something like 2000-01-01 to 2099-01-01) and include columns such as is_working_day which can be set to TRUE/FLASE or 1/0. Then you can update that column as necessary, and join on that table in your query to get working dates that the employee has booked off.
In short, you count the relevant dates, rather than deducting the irrelevant dates.
SELECT
s.employee,
s.taskname,
COUNT(*) AS total_days,
FROM
(
schedule AS s
INNER JOIN
activities AS a
ON a.taskname = s.taskname
)
INNER JOIN
calendar AS c
ON c.calendar_date >= s.startDate
AND c.calendar_date <= s.endDate
AND c.is_working_day >= 1 - a.count_non_working_days
WHERE
c.calendar_date >= '2023-01-01'
AND c.calendar_date <= '2023-12-31'
GROUP BY
s.employee,
s.taskname
Your calendar table can then also include flags such as is_weekend, is_bank_holiday, is_fubar, is_amazing, etc, and the is_working_day can be a computed column from those inputs.
Note on is_working_day filter...
WHERE
( count_non_working_day = 1 AND is_working_day IN (0, 1) )
OR
( count_non_working_day = 0 AND is_working_day IN ( 1) )
-- change to (1 - count_non_working_day)
WHERE
( (1 - count_non_working_day) = 0 AND is_working_day IN (0, 1) )
OR
( (1 - count_non_working_day) = 1 AND is_working_day IN ( 1) )
-- simplify
WHERE
( (1 - count_non_working_day) <= is_working_day )
OR
( (1 - count_non_working_day) <= is_working_day )
-- simplify
WHERE
( (1 - count_non_working_day) <= is_working_day )
Demo: https://dbfiddle.uk/YAmpLmVE
This is to calculate all the weeekends between two giving dates It may help you :
SELECT (
((WEEK('2022-12-31') - WEEK('2022-01-01')) * 2) -
(case when weekday('2022-12-31') = 6 then 1 else 0 end) -
(case when weekday('2022-01-01') = 5 then 1 else 0 end)
)
You will have to substract also holidays that fall within this date range.

SQL select by date from today

I'm studying SQL (Using MariaDB 10.2) and I'm using a huge example database I found online. It has an 'employees' table, and this one has a 'birth_date' column of 'date' type. I want to select all those employees who are more than 50 years old, for example, or maybe those who will be 25 years old on an specific date . Is there a way to do something like this?
You can add or subtract intervals to dates:
SELECT *
FROM employee
WHERE birth_date <= NOW() - INTERVAL 50 YEAR
Assuming t-sql, then for those over 50 today, use:
select * from employees where datediff(year, birth_date, now()) > 50
For those who will be 25 on a certain date use:
select * from employees where datediff(year, birthdate, certain_date) = 25
Use this
SELECT * FROM myTable WHERE DATE(myDate) = DATE(NOW())
This is for MySql DB
You can use INTERVAL function which you can add or subtract Dates:
SELECT * FROM employee WHERE birth_date <= (NOW() - INTERVAL 50 YEAR);
NOW() -----> Present Date
-INTERVAL 50 YEAR -----> Subtract that Date to 50 Years

MySQL: How to do date between by year and month (no date)

If there are 2 columns in mysql database: year; month, now I want to do a sum calculation based a year-month range without specifying the date. Let's say 2010-11 to 2011-07, how can I realize it?
SELECT * FROM TT WHERE F1 BETWEEN '2010-11' AND '2011-07'
It doesn't work.
If you want to take all rows from 2010-11 to 2011-07, until the first day of August:
SELECT * FROM `table`
WHERE `date_column` BETWEEN '2010-11-01' AND '2011-08-01'
Use this query if you want to get all rows from the full months of January to June:
SELECT * FROM `table`
WHERE YEAR(`date_column`)=2011 AND MONTH(`date_column`) BETWEEN 1 AND 6
If you want to use different years, then write different queries for each year:
SELECT * FROM `table`
WHERE
(YEAR(`date_column`)=2010 AND MONTH(`date_column`) BETWEEN 11 AND 12) OR
(YEAR(`date_column`)=2011 AND MONTH(`date_column`) BETWEEN 1 AND 7)
Try this, if F1 is of type date
SELECT * FROM TT WHERE F1 BETWEEN '2010-11-01' AND '2011-07-31'
and this if F1 is of type datetime
SELECT * FROM TT WHERE F1 BETWEEN '2010-11-01 00:00:00' AND '2011-07-31 23:59:59'
if year and month are saved in different columns then use this
SELECT * FROM TT WHERE DATE(CONCAT(year_column, '-', month_column, '-01'))
BETWEEN '2010-11-01' AND '2011-07-31'
I came across to the same situation and successfully managed by doing this:
SELECT * FROM `TT` WHERE CONCAT(year_column,month_column) between '201011' and '201107';
hope it helps others also..

Get all records between two weeks

I need to get all records between two week numbers. This is the query I'm using right now:
SELECT huxwz_user_orders . * , huxwz_users.name, huxwz_users.email FROM huxwz_user_orders
LEFT OUTER JOIN huxwz_users ON ( huxwz_user_orders.userid = huxwz_users.id )
WHERE
(STATUS=3 or STATUS=2)
AND plannedweek > 0
AND plannedweek >= WEEK(DATE_ADD(now(), interval 1 WEEK))
AND plannedweek < WEEK(DATE_ADD(now(), interval 3 WEEK))
AND NOT plannedweek=0
The query works very well and returns all records between the two provided weeks. HOWEVER When I add like 16 to the < ending of the query. MySQL interprets the 16 weeks should be added to the current week (42), So it's 16+42 = 58. Since we dont have 58 weeks and only 52, it must be the sixth week. This is exactly how it should do.
Problem is, when I want to find all records between two values and it does like above. It's going to look like this:
Get all records that are > 42 and < 16. This makes no sense, and it will obviously not return anything.
So, my records have a year, so I do know what year it is. I was thinking something along the lines: If the week, is next year, add 52 to the value. This is unreliable though, since not every year has 52 weeks.
How would I do this?
Any suggestions / solutions?
It looks like #Strawberry's comment is on the right track.
I corrected Strawberry's omission of the DATE_ADD() function, plus we need to adapt the value of planned week to match the results of the YEARWEEK() function.
e.g.:
SELECT huxwz_user_orders . * , huxwz_users.name, huxwz_users.email FROM huxwz_user_orders
LEFT OUTER JOIN huxwz_users ON ( huxwz_user_orders.userid = huxwz_users.id )
WHERE
(STATUS=3 or STATUS=2)
AND plannedweek > 0
AND (YEAR( NOW() ) * 100) + plannedweek >= YEARWEEK( WEEK(DATE_ADD(now(), interval 1 WEEK)), 1)
AND (YEAR( NOW() ) * 100) + plannedweek < YEARWEEK( WEEK(DATE_ADD(now(), interval 3 WEEK)), 1)
AND NOT plannedweek=0
If this doesn't work then your question may need some further clarification.

Rolling 30 day uniques in sql

Suppose you have a table of the form:
create table user_activity (
user_id int not null,
activity_date timestamp not null,
...);
It's easy enough to select the number of unique user_id's in the past 30 days.
select count(distinct user_id) from user_activity where activity_date > now() - interval 30 day;
But how can you select the number of unique user_ids in the prior 30 days for each of the past 30 days? E.g. uniques for 0-30 days ago, 1-31 days ago, 2-32 days ago and so on to 30-60 days ago.
The database engine is mysql if it matters
You could try using a sub query:
SELECT DISTINCT `activity_date` as `day`, (
SELECT count(DISTINCT `user_id`) FROM `user_activity` WHERE `activity_date` = `day`
) as `num_uniques`
FROM `user_activity`
WHERE `activity_date` > NOW() - INTERVAL 30 day;
This should give you the number of unique users for each day. However, I haven't tested this since I don't have the DB to work with.
I haven't tried this in MySQL, but hopefully the syntax is right. If not, maybe it will point you in the right direction. First, I often employ a Numbers table. It can be a physical table simply made up of numbers or it can be a generated/virtual/temporary table.
SELECT
N.number,
COUNT(DISTINCT UA.user_id)
FROM
Numbers N
INNER JOIN User_Activity UA ON
UA.activity_date > NOW() - INTERVAL 30 + N.number DAY AND
UA.activity_date <= NOW() - INTERVAL N.number DAY
WHERE
N.number BETWEEN 0 AND 30
GROUP BY
N.number
I'm not familiar with the whole INTERVAL syntax, so if I got that wrong, please let me know and I'll try to correct it.
If you get the days number for todays date and mod it by 30 you get the offset of the current day. Then you add that to each number for a date and divide the result by 30, this gives you the group of days. Then group your results by this number. So in code something like this:
select count(distinct user_id), (to_days(activity_date)+(to_days(now()) % 30)) / 30 as period
from user_activity
group by (to_days(activity_date)+(to_days(now()) % 30)) / 30
I will leave calculating the reverse numbering of period up to you (hint: take the period number for the current date as "max" and subtract period above and add 1.)