mySQL average of all maximum value - mysql

I have table score like this.
Then I use query to get the maximum or highest average,
SELECT stud_num, assess_type, MAX(average) FROM score
WHERE assess_type = "general" OR assess_type = "professional"
OR assess_type = "specialization"
GROUP BY stud_num, assess_type;
Result is,
But I want to add every maximum value per ID and get the average.
like student #1 = 70 +80 / 3, student #2 = 62.5 + 76 + 72 / 3 etc.
It is possible to do this in one query?
Desire output is
stud_num | average
1 50 //avg of general, prof, special
2 71.5
3 72.16

This must solve your problem. Give it a try:
SELECT stud_num
, (SUM(max_average)/3) as final_average
, access_type
FROM
( SELECT stud_num
, access_type
, MAX(average) as max_average
from score
where access_type IN ('general', 'professional', 'specialization')
GROUP
BY stud_name
, access_type
) as temp_score
GROUP
BY stud_num

Related

Mysql join table group by user id and score result with set max date

I am developing a WordPress website for e learning. So one student attends the course, many times and scored the mark many times. Now I need to get one id with score and last record. I have tried many examples, but am able to get the result. I have given below my code.
SELECT m.id
, m.email
, t.id_tracking
, t.user_id
, FROM_UNIXTIME(t.date)
, t.score
, t.groupe_id
FROM tracking t
join membres m
WHERE t.id_tracking IN (
SELECT MAX(date)
FROM tracking
GROUP BY user_id
)
I have used about the query I don't know what I did wrong
user_id email score date
1 test#testmail.com 78 15-06-2019
1 test#testmail.com 89 12-08-2019
2 sam#testmail.com 66 24-03-2018
2 sam#testmail.com 44 19-07-2019
3 siv#testmail.com 98 09-02-2019
3 siv#testmail.com 78 13-08-2020
I need to get result below like
user_id email score date
1 test#testmail.com 89 12-08-2019
2 sam#testmail.com 44 19-07-2019
3 siva#testmail.com 98 09-08-2020
You can GROUP BY email/user_id and select maximum of date from each group, by converting the date to a UNIX TIMESTAMP, like this
SELECT user_id, email, score, FROM_UNIXTIME(MAX(UNIX_TIMESTAMP(date)))
FROM tableName
GROUP BY user_id
I am not sure about your DB but,
Have you tried like this...
SELECT
*
FROM
(SELECT * FROM process_table ORDER BY date desc) tbl1
GROUP BY
tbl1.id

Number duplicate records on the MySQL table

Have a table with similar schema
id control code amount
1 200 12 300
2 400 12 300
3 200 12 300
4 100 10 400
5 100 10 400
6 500 13 500
Trying to list the duplicates of records on a UI.
Using following query I can retrieve the duplicate records and show it on UI.
select * from mwt group by control,code,amount having count(id) > 1;
id control code amount
1 200 12 300
4 100 10 400
Here the records with id 1 and 4 are duplicates of 3 and 5 respectively.
On the UI, the user will click a check-box adjacent to the record and corresponding duplicate records should be populate to the UI. To make things easier trying to populate another column named dup_id. Using this dup_id it is possible to filter the results from UI , which is in the JSON format.
How to create a result set similar to the one shown below?
id control code amount dup_id
1 200 12 300 1
2 400 12 300
3 200 12 300 1
4 100 10 400 4
5 100 10 400 4
6 500 13 500
This seems like a simpler solution than that suggested by #kickstarter - but maybe I've misunderstood the requirement...
SELECT x.*
, y.dup_id
FROM my_table x
LEFT
JOIN
( SELECT MIN(id) dup_id
, control
, code
, amount
FROM my_table
GROUP
BY control
, code
, amount
HAVING COUNT(*) > 1
) y
ON y.control = x.control
AND y.code = x.code
AND y.amount = x.amount;
Depending on how accurate the order has to be, you could do something like this.
This is getting all the unique control / code / amount with a count, to get a flag to know if that is a duplicate row, and ordered by control / code / amount so that they are in order. It does a cross join to initialise a few user variables.
Then it calculates a counter, only incrementing it if any of control / code / amount have changed AND it is a duplicate row. Then sets user variables to store the previous values of control / code / amount.
The outer query then orders the results back in to id order.
SELECT sub3.id,
sub3.control,
sub3.code,
sub3.amount,
sub3.dup_id
FROM
(
SELECT sub2.id,
sub2.control,
sub2.code,
sub2.amount,
#cnt:=IF(#control=control AND #code=code AND #amount=amount AND sub2.id_count IS NOT NULL, #cnt, IF(sub2.id_count IS NULL, #cnt, #cnt + 1)),
#control:=control,
#code:=code,
#amount:=amount,
IF(sub2.id_count IS NULL, NULL, #cnt) AS dup_id
FROM
(
SELECT mwt.id, mwt.control, mwt.code, mwt.amount, sub1.id_count
FROM mwt
LEFT OUTER JOIN
(
SELECT control, code, amount, COUNT(id) AS id_count
FROM mwt
GROUP BY control,code,amount
HAVING id_count > 1
) sub1
ON mwt.control = sub1.control
AND mwt.code = sub1.code
AND mwt.amount = sub1.amount
ORDER BY mwt.control, mwt.code, mwt.amount
) sub2
CROSS JOIN
(
SELECT #cnt:=0, #control:=0, #code:=0, #amount:=0
) sub0
) sub3
ORDER BY id
Note that this is ordering by control, code and amount, so not an exact match for your required output (which would require getting the first duplicates ordered by id first).
EDIT - Simpler and better way to do it. This gets all the duplicate rows with the min id for those duplicates (ordered by the min id), and uses a user variable to add a sequence number for those. Then LEFT OUTER JOINs that back against the main table to put that sequence number in all the matching rows.
SELECT mwt.id, mwt.control, mwt.code, mwt.amount, sub2.dup_id
FROM mwt
LEFT OUTER JOIN
(
SELECT sub1.id, sub1.control, sub1.code, sub1.amount, #cnt:=#cnt+1 AS dup_id
FROM
(
SELECT MIN(id) AS id, control, code, amount
FROM mwt
GROUP BY control,code,amount
HAVING COUNT(id) > 1
ORDER BY id
) sub1
CROSS JOIN
(
SELECT #cnt:=0
) sub0
) sub2
ON mwt.control = sub2.control
AND mwt.code = sub2.code
AND mwt.amount = sub2.amount
ORDER BY mwt.id
Would you need a dup_id column ?. I hope this can be achieved with a simple query like below
select id
, control
, code
, amount
from table
where control = from selected Record
and code = from selected Record
and amount = from selected Record
and id not equals from selected Record
You can very well omit the last not equals if the requirement is to list down duplicates including the selected record.

which customer number(numbers) occur max time in a table

I have a table ORDERS which has something like this value ,
customerNumber | orderNumber(PK)
40 1
30 2
40 3
20 4
30 5
So, this table has customerNumbers 40 and 30 placing the max orders. Can anyone tell me a MySQL query to return the customerNumber (numbers), i dont want the count of the orders, just want the customer (cutomers) with the max order placed .
Thanks.
You can use below statement to get the Customer who placed maximum orders.
SELECT customerNumber FROM orders
GROUP BY customerNumber
ORDER BY COUNT(orderNumber) DESC LIMIT 1;
I should get deservedly flamed for this, but hey, the sun's out and it's feeling like a good day...
SELECT x.customernumber
FROM
( SELECT customernumber
, COUNT(*) total
FROM my_table
GROUP
BY customernumber
) x
JOIN
( SELECT COUNT(*) total
FROM my_table
GROUP
BY customernumber
ORDER
BY total DESC
LIMIT 1
) y
ON y.total = x.total;

MySQL: How can I use SQL_CALC_FOUND_ROWS with LIMIT and at the same get the SUM of a column?

So SQL_CALC_FOUND_ROWS can be used together with LIMIT to get all items needed. But my problem is that I also want to get the SUM of a column of all those items. I tried the following:
"SELECT SQL_CALC_FOUND_ROWS *, SUM('score') FROM `tab` WHERE 1
LIMIT 1, 10"
Interestingly, it returns only one item instead of 10 as it is supposed to. I am pretty sure it is caused by the SUM function as when I remove the SUM function, it returns 10 items correctly. So how do I achieve what I want and why the above one is not working?
To be concise, take the following table as an example:
id name score
1 abc 10
2 def 20
3 abc 30
I would like to return the following results:
id name score total_score
1 abc 10 40
2 def 20 20
3 abc 10 40
Another related question is: I know that total_score is repeating itself for the same user. So the related question is: Is using one query (if it is possible) better than two queries in this case?
You will need to use the GROUP BY clause along with using an aggregation function like SUM.
For example, if your structure was something like this:
create table tab (
id int auto_increment primary key,
gamename varchar(20),
score int
);
insert into tab (gamename, score) values
('game1', 20),
('game2', 30),
('game3', 40),
('game2', 60);
Your query to extract the sum would look like this:
SELECT SQL_CALC_FOUND_ROWS gamename, SUM(score)
FROM `tab`
group by gamename
LIMIT 1, 10;
-- Results
gamename sum(score)
-------- ----------
game2 90
game3 40
select found_rows();
found_rows()
------------
3
Hope this helps out.
Corresponding edit to the question
select SQL_CALC_FOUND_ROWS a.*, b.totals
from tab a
inner join (
select gamename, sum(score) as totals
from tab
group by gamename
) b on a.gamename = b.gamename
limit 0, 2;
-- Result
id gamename score totals
-- -------- ----- ------
1 game1 20 20
2 game2 30 90
select found_rows();
found_rows()
------------
4

SELECT rows with minimum count(*)

Let's say i have a simple table voting with columns
id(primaryKey),token(int),candidate(int),rank(int).
I want to extract all rows having specific rank,grouped by candidate and most importantly only with minimum count(*).
So far i have reached
SELECT candidate, count( * ) AS count
FROM voting
WHERE rank =1
AND candidate <200
GROUP BY candidate
HAVING count = min( count )
But,it is returning empty set.If i replace min(count) with actual minimum value it works properly.
I have also tried
SELECT candidate,min(count)
FROM (SELECT candidate,count(*) AS count
FROM voting
where rank = 1
AND candidate < 200
group by candidate
order by count(*)
) AS temp
But this resulted in only 1 row,I have 3 rows with same min count but with different candidates.I want all these 3 rows.
Can anyone help me.The no.of rows with same minimum count(*) value will also help.
Sample is quite a big,so i am showing some dummy values
1 $sampleToken1 101 1
2 $sampleToken2 102 1
3 $sampleToken3 103 1
4 $sampleToken4 102 1
Here ,when grouped according to candidate there are 3 rows combining with count( * ) results
candidate count( * )
101 1
103 1
102 2
I want the top 2 rows to be showed i.e with count(*) = 1 or whatever is the minimum
Try to use this script as pattern -
-- find minimum count
SELECT MIN(cnt) INTO #min FROM (SELECT COUNT(*) cnt FROM voting GROUP BY candidate) t;
-- show records with minimum count
SELECT * FROM voting t1
JOIN (SELECT id FROM voting GROUP BY candidate HAVING COUNT(*) = #min) t2
ON t1.candidate = t2.candidate;
Remove your HAVING keyword completely, it is not correctly written.
and add SUB SELECT into the where clause to fit that criteria.
(ie. select cand, count(*) as count from voting where rank = 1 and count = (select ..... )
The HAVING keyword can not use the MIN function in the way you are trying. Replace the MIN function with an absolute value such as HAVING count > 10