some select queries that use date format - mysql

So.. to return the age based on a date type it's really easy :
SELECT YEAR(CURDATE()) - YEAR(DateofBirth) and we get a result set with the age of the person
But what if I need to search the people with an age range of 60-70 in the table based on their date of birthdays in this format d/m/y ( Ex: 2005-04-11). I considered it was kind of hard because it's a different thing searching for an certain age if u have only dateofbirths instead of searching through a column where u already have their ages being counted as normal years ( 50, 60 etc )
Another problem that's not related to the one mentioned above:
Let's say I have a table with Medics that has their names, surnames and their speciality.
We got 17 specialities : reumatologie, o.r.l, chirurgie etc. and 108 doctors
How do I get the list of the medical specialities and the doctors that are in that range based on this format:
Ex: reumatologie - 4, o.r.l - 5, chirurgie - 10 etc
4 and 5 from the examples are the number of medics. I've tried concatenating and all sort of queries none of them worked properly though. Maybe will work with a case? if yes how?

For question 1, you can just do (not very good regarding performance though):
SELECT YEAR(CURDATE()) - YEAR(DateofBirth) AS age
FROM tableX
WHERE (YEAR(CURDATE()) - YEAR(DateofBirth)) BETWEEN 60 AND 70 ;
If you want performance, you can add an index on DateofBirth and use this version:
SELECT YEAR(CURDATE()) - YEAR(DateofBirth) AS age
FROM tableX
WHERE DateofBirth >= MAKEDATE(YEAR(CURDATE())-70, 1)
AND DateofBirth < MAKEDATE(YEAR(CURDATE())-60+1, 1) ;

Related

MySql query with dates in NodeJs

i have a table in MySQL database of people, with their Birthrates.
for example '1991-11-21'
I have two values, one is minimum age(like 22), and the other is maximum age(like 33).
I would like to make a query that gets me all the records with people between the minimum age value, and the maximum.
I am working with NodeJs.
any ideas?
One solution is to do all the work in MySQL and inject your variables into your MySQL statement
To do that you will need a combination of these answers
1) Get the date from x years ago
Selecting all records from one year ago till now
2) Select results between date range
Select mysql query between date?
You should end up with a query something like this:
select *
from *table_name*
where *datetime_column*
between DATE_SUB(NOW(),INTERVAL 22 YEAR)
and DATE_SUB(NOW(),INTERVAL 33 YEAR);
Note: you may need to add a year to the second date (33+1) to get the full range of someones age being 33 (you are 33 until the day you turn 34)
Or if you prefer you can calculate your dates in JS, but depending how you do it you may need to format your dates so they will work in your query
Try this :
SELECT age, birthday FROM tablename WHERE age > 22 AND age < 33
I took this in wrong way :
i think here is correct :
SELECT *, TIMESTAMPDIFF(YEAR,birthday,CURDATE()) as age FROM student WHERE TIMESTAMPDIFF(YEAR,created,CURDATE()) > 22 AND TIMESTAMPDIFF(YEAR,birthday,CURDATE()) < 33

Number of rows returned when adding before/after date logically inconsistant

I have a database containing information about a students visit to our tutoring center. Each time a student visits a record is produced which includes their names, their student number the date they visited, what they were there for and how long they were there.
We create new tables for each term
I was asked to get an unduplicated count of how many students were there during a certain term so I run the following.
SELECT * FROM `tutoringdata_201350` group by `anum`
anum being the students unique identification number, which returns 524 results out of 5525 total records. In theory that should be my unduplicated count.
I was then asked to get records before and after a certain date in that same table, so I run.
SELECT * FROM `tutoringdata_201350` WHERE `cDate` <= "09/30/2013" group by `anum`
Which works, so far as the date is concerned and no duplicate people are returned so far as I can see in the results window if I sort by the anumber they are all unique. BUT the total number of results returned is 375
So to get students after that date I run
SELECT * FROM `tutoringdata_201350` WHERE `cDate` > "09/30/2013" group by `anum`
which also appears to work, no duplicated students in the returned results but total number of returned results is 428.
375 + 428 is 803 not 524 which I would expect. I'm having trouble following the logic, which of the 2 different types of queries are producing an inaccurate number of results.
You are misusing the pernicious nonstandard MySQL extension to GROUP BY. http://dev.mysql.com/doc/refman/5.6/en/group-by-handling.html
You probably want something like this;
SELECT COUNT(DISTINCT anum) unique_students
FROM `tutoringdata_201350`
WHERE cDate <= 'whatever'
You could also do this to find out how many visits each student made.
SELECT COUNT(*) visits,
anum
FROM `tutoringdata_201350`
WHERE cDate <= 'whatever'
GROUP BY anum
You are also, I think, making a mistake in the way you are comparing dates.
MySQL uses an internal DATE and DATETIME format. If you want to compare such data items in your table to a text-string constant, you need to use the correct format -- YYYY-MM-DD -- for that string. For example:
WHERE cDate <= '2013-09-30'
The comparison in your example isn't correct. Edit. If your dates are stored as text strings as MM/DD/YYYY, you need to use the following sort of comparison.
WHERE STR_TO_DATE(cDate, '%m/%d/%Y') <= '2013-09-30'
This will convert your legacy date strings to DATE format. Then the comparison will work. If you don't do this MySQL is just comparing strings to strings. (You may, or may not, luck out if the years don't vary.)
Now, your counts of unique students before and after the first of October do not necessarily sum up to the count of unique students for the whole term. Here's an example.
Joe Sept 28
Joe Sept 29
Mary Sept 30
Henry Sept 30
Joe Oct 1
Stephen Oct 1
Overall there are four distinct students. In Sept there are three. In October there are two. If you add those two numbers you get five. That's more because you're double-counting Joe by adding those two numbers.

Group By date SQL Query on a fact table

I have this fact table here, I would like using this table to list group by year and have the total number of patients that have PatientType_id = 1101.
Example:
2012 5
2012 8
The Date_DateKey is actually the date 2012-03-14. I've managed to list the total patients with typeID 1101 for a single year, but I don't know how is possible to list all the years. Could you give me some hints please?
And here's the Date dimension
Normally, a key column in a fact table would reference another table. So, you should have a date/calendar table somewhere with information like the year. That would be the proper way to get this information.
I discourage you from parsing key values in general. In this case, with the information you have provided, it seems to be the only solution:
select floor(date_datekey / 10000) as year, count(distinct patient_id)
from table t
where PatientType_id = 1101
group by floor(date_datekey / 10000)
Try this:
SELECT LEFT(DateKe,4) as Year, COUNT(patient_id) FROM Table WHERE PatientType_id = 1101 GROUP BY LEFT(DateKe,4)

TSQL SELECT based on a condition

I am trying to do a select from CTE based on a condition.
There is a variable I've declared for today's period (#PRD). It holds the value of what period we are currently in.
Now I would like to do a selection from a table that will restrict what information is returned based on whether we are in the first half of the year or not.
For instance, we are in period 2 so I want everything returned from my CTE which falls between PRD 1 and 5. IF we were in say period 6 (after 5), then yes I'd want everything returned from the table.
This is the pseudocode of what I'm trying to accomplish:
SELECT
CASE
WHEN #PRD <= 5
THEN (SELECT * FROM DISPLAY WHERE PERIOD IN (1,2,3,4,5))
ELSE (SELECT * FROM DISPLAY)
END
I'm getting an error:
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
Please any thoughts on how I can do this?
Thanks x
EDITED/UPDATED:
More of the code involves a CTE and is really long. Bottom line is lets say I have this CTE
;WITH DISPLAY as (
select * from lots_of_things
)
SELECT * FROM DISPLAY
Having done a regular select on this CTE, it returns data that looks like this:
PERIOD (INT) DEPARTMENT GROUP BUDGET
1 ENERGY HE 500
2 ENERGY HE 780
3 ENERGY HE 1500
4 ENERGY HE 4500
5 ENERGY HE 400
6 ENERGY HE 3500
7 ENERGY HE 940
8 ENERGY HE 1200
I want it to show me just the top 5 rows if we the current period is 1,2,3,4,5. But to display ALL table rows if we are in any other period like 6,7,8,9 and onwards. The current period is held in the variable #PRD which is derived from doing a comparison of today's date with ranges held in a table. The value is accurate and also type INT
Hope this helps
SQL FIDDLE
This will work:
SELECT * FROM DISPLAY WHERE (#PRD > 5 OR PERIOD IN (1, 2, 3, 4, 5))
If this code confuses you, what's happening is that we check if #PRD > 5 and if that returns true, our expression is always true so we return all the rows.
If the variable is less or equal to 5 (like you checked in your example), the first check is false and then we check if the period is the list.
This might be a solution:
IF #PRD <= 5
SELECT * FROM DISPLAY WHERE PERIOD IN (1,2,3,4,5)
ELSE
SELECT * FROM DISPLAY
UPD
In this case you should use variable instead of CTE, if it's possible.
DECLARE #PRD INT;
SELECT #PRD = PERIOD FROM SOME_TABLE WHERE ...

SQL - getting totals from a crosstab query

TRANSFORM Count(Research.Patient_ID) AS CountOfPatient_ID
SELECT DateDiff("yyyy",[DOB],Date()) AS [Age Group 22 - 24]
FROM (Research INNER JOIN Demographics ON Research.Patient_ID = Demographics.ID) INNER JOIN [Letter Status] ON Research.Patient_ID = [Letter Status].Patient_ID
WHERE (((DateDiff("yyyy",[DOB],Date())) Between 22 And 24))
GROUP BY DateDiff("yyyy",[DOB],Date())
PIVOT [Letter Status].Letter_Status;
This code lists individual ages, but I want to calculate the Total of all ages that fall within that range. So if there were two 22 year olds, and one 23 year old, the Total would be 3, as opposed to seeing all of their individual ages in the column...
Please help.
Please be sure you understand what you're getting when you use this method to determine a person's age.
DateDiff("yyyy",[DOB],Date())
If DOB = #1987-12-31#, on today's date (#2011-6-16#), DateDiff will give you this as the age:
? DateDiff("yyyy", #1987-12-31#, #2011-6-16#)
24
(And actually for any DOB during 1987, DateDiff with today's date would give you 24 as the "age". Furthermore, for any DOB during 1987, using that method on any day in 2011, you would get 24.)
OTOH, as age is commonly understood, one might say "Nonsense! His birthday is still more than 6 months away. He's only 23 today."
The reason for this discrepancy is that DateDiff("yyyy" only evaluates the year component of two dates. Consider these two dates which are one day apart:
? DateDiff("yyyy",#2010-12-31#,#2011-1-1#)
1
That same thing happens when you use that expression to calculate "age".
To return the age as commonly understood, you can use an expression like this:
? DateDiff("yyyy", #1987-12-31#, Date())+ _
Int( Format(Date(), "mmdd") < Format( #1987-12-31#, "mmdd"))
I copied that expression from the Access Web: Calculate Age of a person. That page includes other approaches for determining age.
None of this matters if, apparently like the OP, you want all DOB in 1987 to be counted as age 24 today, or on any day in 2011.
You need to define the age ranges in a switch statement. To make it easier I've created a inline query to calcuate the age (I'm assuming its on the research table).
TRANSFORM Count(Research.Patient_ID) AS CountOfPatient_ID
SELECT SWITCH (Age <= 22, "Under 22",
Age > 22 and AGE <= 24 , "Between 22 And 24",
Age > 24 and AGE <= 26, "Between 24 And 26",
Age > 26 , "Over 26") as Age_Range
FROM
(Research
INNER JOIN (SELECT ID, DateDiff("yyyy",DOB,Date()) as AGE
FROM Demographics) Demographics
ON Research.Patient_ID = Demographics.ID)
INNER JOIN [Letter Status]
ON Research.Patient_ID = [Letter Status].Patient_ID
GROUP BY AGE
PIVOT [Letter Status].Letter_Status;