mysql group by on sum column - mysql

I am having a scenario where students of a college do a research on a subject. Each subject has some value (marks) for it. A student can do research on multiple subjects.
I have the following table hierarchy:
student (s)
---------------
student_id subject_id
1 2
2 1
2 3
3 1
3 3
4 2
4 3
.....
research_subjects (r)
-----------------------------
id value
1 5
2 10
3 20
4 40
....
Now i am fetching the student records along with their total research value with this query:
select student_id, sum(r.value) as total from student s inner join research_subjects r on s.subject_id=r.id group by student_id
This gives results like the following:
student_id total
1 10
2 25
3 25
4 30
As you see, the results are grouped by student_id. But what i want is to group the results by total value. So i want to get rid of duplicate rows for the total, in the output. (i.e., have only 1 record with the total=25).
I tried using: group by total in the query (instead of group by student_id), but it gives an error.
Is there any other way of grouping the results by the column that contains 'sum' value?

Try this:
select count(student_id), total
from (
select student_id, sum(r.value) as total
from student s
inner
join research r on s.subject_id=r.id group by student_id
) s2
group by total

Try this:
select Count(student_id) as students, total
from
(
select student_id, sum(r.value) as total
from student s inner join research r on s.subject_id=r.id
group by student_id
) s
group by total
Or this:
select Min(student_id) as student_id, total
from
(
select student_id, sum(r.value) as total
from student s inner join research r on s.subject_id=r.id
group by student_id
) s
group by total

Related

SQL: How to join two tables and extract the data by timestamp?

I'm using mysql. I have two tables, one is about movie type, and the other is about movie rating with timestamps. I want to join these two tables together with movie id to count the average rating for each type of movie. I'm trying to extract only the movie types which have at least 10 ratings per film and the ratings made in December, and order by the highest to lowest average rating.
Table 'types'
movieId
type
1
Drama
2
Adventure
3
Comedy
...
...
Table 'ratings'
movieId
rating
timestamp
1
1
851786086
2
1.5
1114306148
1
2
1228946388
3
2
850723898
1
2.5
1167422234
2
2.5
1291654669
1
3
851345204
2
3
944978286
3
3
965088579
3
3
1012598088
1
3.5
1291598726
1
4
1291779829
1
4
850021197
2
4
945362514
1
4.5
1072836909
1
5
881166397
1
5
944892273
2
5
1012598088
...
...
...
Expect result: (Nb ratings >= 10 and rate given in December)
type
Avg_Rating
Drama
3.45
I'm trying to write the query like below, but I'm not able to execute it. (around 10 thousand data in original table)
Where should I adjust my query?
SELECT DISTINCT T.type, AVG(R.rating) FROM types AS T
INNER JOIN ratings AS R ON T.movieId = R.movieId
WHERE R.timestamp LIKE (
SELECT FROM_UNIXTIME(R.timestamp,'%M') AS Month FROM ratings
GROUP BY Month
HAVING Month = 'December')
GROUP BY T.type
HAVING COUNT(R.rating) >=10
ORDER BY AVG(R.rating) DESC;
I see two problems:
timestamp LIKE - what's that supposed to do?
and
inner query with GROUP BY by without any aggregation. Perhaps you meant WHERE? And anyway you don't need it at all - just do the same check for December directly on timestamp, w/o LIKE and w/o subquery
SELECT DISTINCT T.type, AVG(R.rating) FROM
types AS T INNER JOIN ratings AS R 
ON T.movieId = R.movieId
WHERE FROM_UNIXTIME(R.timestamp,'%M') = 'December'
GROUP BY T.type
HAVING COUNT(R.rating) >=10
ORDER BY AVG(R.rating) DESC;
You can try next query.
SELECT DISTINCT T.type, AVG(R.rating) FROM types AS T
INNER JOIN ratings AS R ON T.movieId = R.movieId
GROUP BY T.type
HAVING
COUNT(R.rating) >= 10 -- have 10 or more rating records
AND SUM(MONTH(FROM_UNIXTIME(R.timestamp)) = 12) > 0 -- have at least one rating in December
ORDER BY AVG(R.rating) DESC;
sqlize

name and sum from 2 different tables

I have 2 tables.
table customer have. id , name , age
table order have . id, customer_id , order_amount , order date.
I want to show all name from customer table and sum of order amount from order table according to customer.
customer_id
Name
age
1
Alice
24
2
Bob
52
3
Carol
45
4
Dave
51
order_id
customer_id
order_amount
order_date
1
2
50
2012-4-5
2
1
27
2012-8-1
3
2
12
2013-5-20
4
4
25
2014-1-25
5
4
30
2014-5-30
6
1
20
2014-6-22
EDIT
I tried this but it gives me only bob and sum of all columns instead of separate sum of customers
SELECT customers.name, SUM(orders.order_amount) FROM `orders` INNER JOIN customers WHERE orders.customer_id = customers.customer_id;
Joining condition must be on ON clause, not in WHERE.
You must specify for what group the sum must be calculated.
SELECT customers.name, SUM(orders.order_amount)
FROM `orders`
INNER JOIN customers ON orders.customer_id = customers.customer_id
GROUP BY customers.name;

MySql count the total number of the row with a value that occurs at least two times

I want to select the total number of different class_id in which at least two students who share the same the birthday.
class_id student_id birthday
1 30 1994-10-01
1 23 1994-01-01
1 19 1994-02-01
1 11 1994-03-01
2 9 1994-02-01
2 43 1994-03-01
3 41 1994-06-01
3 21 1994-05-01
4 9 1992-05-22
4 20 1992-09-05
Write a subquery that finds all the duplicate birthdays in the same class. Then count the number of different classes with SELECT COUNT(DISTINCT class_id) from that subquery.
SELECT COUNT(DISTINCT class_id) FROM (
SELECT class_id, birthday
FROM YourTable
GROUP BY class_id, birthday
HAVING COUNT(*) > 1) AS x
In the inner select group by the class_id and take only those that have different numbers of unique and total birthdays.
Then count those class_ids in the outer select.
select count(*)
from
(
select class_id
from your_table
group by class_id
having count(*) > count(distinct birthday)
) tmp

SQL: Fetch rows having a column (group by column) being the MAX value

I would like to know how to retrieve rows matching the maximum value for a column.
SCHEMA
assignments:
id student_id subject_id
1 10 1
2 10 2
3 20 1
4 30 3
5 30 3
6 40 2
students:
id name
10 A
20 B
30 C
subjects:
id name
1 Math
2 Science
3 English
Queries:
Provide the SQL for:
1. Display the names of the students who have taken most number of assignments
2. Display the names of the subjects which have been taken the most number of times
Results:
1.
A
C
2.
Math
English
Thanks !
The previous answer is not quite right - you won't get the instances where there are two with the same count. Try this - the second will be easy to replicate once understand the concept.
SELECT a.student_id, s.name, COUNT(a.subject_id) as taken_subjects
FROM assignments a
INNER JOIN students s ON a.student_id = s.id
GROUP BY a.student_id, s.name
HAVING COUNT(a.subject_id) = (SELECT COUNT(*) FROM assignments GROUP BY student_id LIMIT 1)
Alternate query:
SELECT a.subject_id, s.subject_name, COUNT(a.subject_id) FROM assignment a, subjects s
WHERE a.subject_id = s.subject_id
GROUP BY a.student_id, s.subject_name
HAVING COUNT(a.subject_id) = (SELECT MAX(COUNT(1)) FROM assignment GROUP BY subject_id)

MySQL: Find the average value per entry for the last x records

I'm trying to figure out how to grab the average rating for each salesperson over their last 100 ratings if they are currently employed, and if they have an average rating less than 3 (out of 5).
I have the following tables (leaving out information that isn't needed in the query):
users
id name employed
-----------------------
1 John 1
2 Sue 1
3 Bob 0
...
sales
id users_id
------------------
100 3
101 2
102 3
103 1
...
ratings
sales_id rating
-----------------
100 4
101 5
102 5
103 2
...
The current query I have searches everything and returns the average for all orders ever but I want it to only grab the most recent 100 ratings (or less if the salesperson hasn't sold that many items), still excluding anyone that is no longer employed or has a rating for their last 100 orders greater than 3. This is the current query:
SELECT u.name, avg(r.rating) as avg_rating, count(r.rating)
FROM users AS u
JOIN sales AS s ON s.users_id = u.id
JOIN ratings AS r ON r.sales_id = s.id
WHERE u.employed = 1
GROUP BY u.id
HAVING avg_rating <= 3;
Any help would be great! Thanks! :D
You can use my sql variables to keep track of the number of ratings so that you can get only recent 100 ratings , ordering by sales_id so you get recent ratings.
SQL FIDDLE DEMO
SELECT T.name, avg(T.rating) as avg_rating, count(T.rating)
FROM
(
SELECT u.name, r.rating, #num := if (#name = name, #num+1, 1) as rn,
#name:= name as var_name
FROM users AS u
JOIN sales AS s ON s.users_id = u.id
JOIN ratings AS r ON r.sales_id = s.id
AND u.employed = 1
JOIN ( select #name :='' , #num :=1) var
order by sales_id desc
)T
where T.rn <=100
GROUP BY T.name
HAVING avg_rating <= 3