I'm needing to get a SQL Query which returns the average age of multiple data inputs in my table
Households
User
Dates
1
2002-01-01
2
2004-06-10
I want to grab both User 1 and 2 date of births and return the average age of them.
Managed to get the age from the date of births using
SELECT *, DATE_FORMAT(FROM_DAYS(DATEDIFF(NOW(), Date)), '%Y') + 0 AS age
FROM Households;
I just can't get the rest of it working to then average the ages out.
Assuming that you are running MySQL, as the syntax of your SQL code suggests.
For starts, I would recommend simplifying the age computation. MySQL provides timestampdiff(), which we can use like so:
select user_id, user_date,
timestampdiff(year, user_date, current_date) age
from houshold
user_id
user_date
age
1
2002-01-01
20
2
2004-06-10
18
3
2004-11-10
17
To compute the average age over all rows of the table, we can use aggregate function avg():
select avg(timestampdiff(year, user_date, current_date)) avg_age
from houshold
avg_age
18.3333
Here is a small demo based on your sample data. Note that I renamed the columns so they do not clash with meaningful SQL names.
Related
I am trying to complete this question, but I am receiving a "Column 'DOG.DOB' is invalid in the HAVING clause because it is not contained in either an aggregate function or the GROUP BY clause." error, but I am stuck because there is no age column and I am confused on how I'm supposed to go about solving it. Below is the question to the problem and below the question is the desired output
Using a subquery, create a query that will show those dogs that are older than the average age of all dogs. In your output include the name of the dog and the age. Since the database does not store the age of a dog, you will need to calculate it. There are numerous functions that can help you to find the difference between two dates. To get the current system date use the getdate() function. Sort your output by the age of the dog showing the older dogs first. Rename your columns: Dog Name and Age. This query will product 359 rows. The first 10 rows will look like the following:
Dog Name Age
--------------- -----------
Rosina 10
Floris 10
Harlin 10
Martina 10
Roselin 10
Rem 10
Alie 10
Roxane 10
Nester 10
Clair 10
My Query:
select Name AS 'Dog Name',
DATEDIFF(year, getdate(), DOB) AS 'Age'
from DOG
having DATEDIFF(year, getdate(), DOB) > avg(DATEDIFF(year, getdate(), DOB))
order by AGE desc
the average calculation needs to be in it's own select statement - which will form the subquery mentioned in the question e.g.
having DATEDIFF(year, getdate(), DOB) > (subquery returning the average age of all dogs)
If anyone could help me with the following, I'd be grateful:
I'm trying to write a code (create an alert in PowerSchool) that will indicate if a student is younger or older than average for their current grade level. (For example, as student born before 6/30/2002 is older than average for 9th grade) I can't seem to make DECODE work in conjunction with >= TO_DATE. Here's my statement:
select lastfirst, decode (dob >= to_date ('2002-06-30', 'yyyy-mm-dd'), 'old') DOB
from students
where grade_level = 9
order by lastfirst
You probably could get away with using a PowerSchool decode in your sql, but I find code easier to write when fewer languages/systems are included, so I would leave it out. I would also let SQL do the average age calculation so you don't have to supply or calculate average dates yourself (see Averaging dates in oracle sql for an explanation of the TO_DATE line).
SELECT
LastFirst AS "Student Name"
,CASE WHEN dob >= (
SELECT
TO_DATE(ROUND(AVG(TO_NUMBER(TO_CHAR(dob, 'J')))),'J')
FROM Students
WHERE Grade_Level = 9
AND Enroll_Status = 0
) THEN 'Younger' ELSE 'Older' END AS "Older or Younger?"
FROM Students
WHERE Grade_Level = 9
ORDER BY LastFirst
The subquery calculates the average birthday, and the CASE statement compares each of your records against that, reporting if it's older or younger.
In the subquery that calculates the average, I've taken the liberty of assuming you only want to compare against currently enrolled students, since withdrawn students retain the same grade level. You don't really want those students who left 10 years ago and are still listed as a 9th grader to mess with your average numbers.
The gem we have installed (Blazer) on our site limits us to one query.
We are trying to write a query to show how many hours each employee has for the past 10 days. The first column would have employee names and the rest would have hours with the column header being each date. I'm having trouble figuring out how to make the column headers dynamic based on the day. The following is an example of what we have working without dynamic column headers and only using 3 days.
SELECT
pivot_table.*
FROM
crosstab(
E'SELECT
"User",
"Date",
"Hours"
FROM
(SELECT
"q"."qdb_users"."name" AS "User",
to_char("qdb_works"."date", \'YYYY-MM-DD\') AS "Date",
sum("qdb_works"."hours") AS "Hours"
FROM
"q"."qdb_works"
LEFT OUTER JOIN
"q"."qdb_users" ON
"q"."qdb_users"."id" = "q"."qdb_works"."qdb_user_id"
WHERE
"qdb_works"."date" > current_date - 20
GROUP BY
"User",
"Date"
ORDER BY
"Date" DESC,
"User" DESC) "x"
ORDER BY 1, 2')
AS
pivot_table (
"User" VARCHAR,
"2017-10-06" FLOAT,
"2017-10-05" FLOAT,
"2017-10-04" FLOAT
);
This results in
| User | 2017-10-05 | 2017-10-04 | 2017-10-03 |
|------|------------|------------|------------|
| John | 1.5 | 3.25 | 2.25 |
| Jill | 6.25 | 6.25 | 6 |
| Bill | 2.75 | 3 | 4 |
This is correct, but tomorrow, the column headers will be off unless we update the query every day. I know we could pivot this table with date on the left and names on the top, but that will still need updating with each new employee – and we get new ones often.
We have tried using functions and queries in the "AS" section with no luck. For example:
AS
pivot_table (
"User" VARCHAR,
current_date - 0 FLOAT,
current_date - 1 FLOAT,
current_date - 2 FLOAT
);
Is there any way to pull this off with one query?
You could select a row for each user, and then per column sum the hours for one day:
with user_work as
(
select u.name as user
, to_char(w.date, 'YYYY-MM-DD') as dt_str
, w.hours
from qdb_works w
join qdb_users u
on u.id = w.qdb_user_id
where w.date >= current_date - interval '2 days'
)
select User
, sum(case when dt_str = to_char(current_date,
'YYYY-MM-DD') then hours end) as Today
, sum(case when dt_str = to_char(current_date - 'interval 1 day',
'YYYY-MM-DD') then hours end) as Yesterday
, sum(case when dt_str = to_char(current_date - 'interval 2 days',
'YYYY-MM-DD') then hours end) as DayBeforeYesterday
from user_work
group by
user
, dt_str
It's often easier to return a list and pivot it client side. That also allows you to generate column names with a date.
Is there any way to pull this off with one query?
No, because a fixed SQL query cannot have any variability in its output columns. The SQL engine determines the number, types and names of every column of a query before executing it, without reading any data except in the catalog (for the structure of tables and other objects), execution being just the last of 5 stages.
A single-query dynamic pivot, if such a thing existed, couldn't be prepared, since a prepared query always have the same results structure, whereas by definition a dynamic pivot doesn't, as the rows that pivot into columns can change between executions. That would be at odds again with the Prepare-Bind-Execute model.
You may find some limited workarounds and additional explanations in other questions, for example: Execute a dynamic crosstab query, but since you mentioned specifically:
The gem we have installed (Blazer) on our site limits us to one
query
I'm afraid you're out of luck. Whatever the workaround, it always need at best one step with a query to figure out the columns and generate a dynamic query from them, and a second step executing the query generated at the previous step.
I have table MYTABLE with columns mydate and quantity of VARCHAR2 type.
|mydate| |quantity|
10/15/2010 15
01/20/2010 20
05/16/2005 30
04/29/2005 50
03/30/2008 5
I want to get:
|year| |quantity|
2010 35
2005 80
2008 5
I try:
SELECT
to_char(mydate,'yyyy') YEAR,
SUM(to_number(quantity))
FROM MYTABLE
GROUP BY
to_char(mydate,'yyyy');
But I get an error
ORA-00979: not a GROUP BY expression
What did I do wrong?
You must put all columns of the SELECT in the GROUP BY or use functions on them which compress the results to a single value (like MIN, MAX or SUM).
A simple example to understand why this happens: Imagine you have a database like this:
FOO BAR
0 A
0 B
and you run SELECT * FROM table GROUP BY foo. This means the database must return a single row as result with the first column 0 to fulfill the GROUP BY but there are now two values of bar to chose from. Which result would you expect - A or B? Or should the database return more than one row, violating the contract of GROUP BY?
Try this
select extract(year from mydate),sum(to_number(quant)) from mytable
group by extract(year from mydate);
SQLFiddle Example
In the sql query, I am getting problem in the where clause.
I have a dob and ssn of people in a table. I need to find the youngest snr. customer. The age of youngest senior customer starts from 55. The data of DOB contains all the dob's of children,parent, senior customers. In the line "where" I have to write a condition that checks if the age is > 55 and has to be smaller amongst the senior customers.Please suggest me some ways .I posted a similar question before, but did nt get any reply that can help me in solving it.
I dont have the age parameter in my table.
SSn DOB
22 1950-2-2
21 1987-3-3
54 1954-4-7
I need to find the ssn corresponding to the age whcih has to be greater than 55 and smaller among above values .
In the script below, the sub-select finds the DOB of the youngest person 55 years of age or over; this is then used to find the corresponding SSN record(s). [This uses SQL Server syntax.]
SELECT yt.*
FROM *yourtable* yt
INNER JOIN
(
SELECT MAX(DOB) AS DOB
FROM *yourtable*
WHERE DATEADD(year, 55, DOB) < getdate()
) maxdob
ON maxdob.DOB = yt.DOB
n.b. you may find more than a single record if there is more than 1 person with the same DOB.
If you want to force this single restriction, add a TOP 1 clause in your SELECT statement.
hth
If you have the DOB then you can easily calculate the age based on the current date:
WHERE DATE_ADD(DOB, INTERVAL 55 YEAR) < NOW()
This will add 55 years to the DOB and if it is greater than the current time, it's true. This would indicate they are at least 55 years of age.