Result of MySQL MAX function - mysql

I'm in trouble understanding how the MAX function works.
Here is my table MD_board :
idPlayer | matchday | total
---------+----------+-------
1 | 7 | 354
---------+----------+-------
2 | 7 | 122
---------+----------+-------
3 | 7 | 672
---------+----------+-------
1 | 8 | 452
---------+----------+-------
2 | 8 | 90
---------+----------+-------
3 | 8 | 654
---------+----------+-------
I want to have the max total and the idPlayer of the matchday 8. But the query is a mystery to me.
I tried the simple query :
SELECT MAX(total), idPlayer FROM MD_board WHERE matchday=8
The max value returned is good ( 654 ) but the idPlayer is wrong ( 1 ).
I tried a lot of other queries but I'm unable to get the correct result :(
I'm not really comfortable about more complex queries, so, if you could help ...

There are three idPlayers for matchday = 8! You probably use MySQL which allows such wrong queries and you should be aware that the MySQL returns random idPlayer value. Therefore, you can obtain different idPlayer tomorrow than you get today for the same query.
You probably want player with highest total in a specific matchday:
SELECT *
FROM MD_board MD1
WHERE matchday=8 and total =
(
SELECT MAX(total)
FROM MD_board MD2
WHERE MD2.matchday = MD1.matchday
)

Your query:
SELECT MAX(total), idPlayer FROM MD_board WHERE matchday=8
By applying MAX without GROUP BY you aggregate your data to one result row. You select the maximum total, which is 654 for that day and the idPlayer for the day. But there is no one player, it's three different ones. This is invalid SQL according to the SQL standard, but MySQL let's this slip and returns one of the three players arbitrarily.
If you want more data from the record(s) with the maximum total, then select those records again:
SELECT *
FROM MD_board
WHERE matchday = 8
AND total = (SELECT MAX(total) FROM MD_board WHERE matchday = 8);

Try this:
SELECT M.*
FROM MD_board M
JOIN (
SELECT matchday,MAX(Total)Total
FROM MD_board
GROUP BY matchday
)D on D.matchday=M.matchday AND D.Total=M.Total

Related

Group by with sum doesn't return correct result

Say a table has this schema :
grp | number
1 | 10
1 | 10
1 | 10
2 | 30
2 | 30
3 | 20
Note that each unique grp has a unique number even if there are more than 1 grp. I'm looking to sum all numbers for each unique grp.
So I want to group my table by grp to have this :
grp | number
1 | 10
2 | 30
3 | 20
And then get the sum which is now 60, but without grouping it gets me 110 as it calculates the sum of everything without grouping. All in one query, with no sub-queries if possible.
I've tried doing the following :
SELECT sum(number) as f
FROM ...
WHERE ...
GROUP BY grp
But this doesn't work, it returns multiple results and not the single result of the sum. What am I doing wrong?
You can use subquery to select unique records & do the sum:
select sum(number)
from (select distinct grp, number
from table t
) t;
If you group by the group, then you'll get one result for each group. And it won't take into account the fact that you only want to use the value from each group once.
To get your desired result, taking one row from each group, you first need to make a subquery selecting DISTINCT group/number combinations from the table, and then SUM that.
SELECT
sum(`number`) as f
FROM
(SELECT DISTINCT `grp`, `number` FROM table1) g
This will output 60.
Demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=8a3b346041731a4b4c85f4e151c10f70

mysql get last N records with MAX(date)

So I have following data in a product_rate_history table -
I want to select last N records ( eg 7 records ) informing rate change history of given product. If product rate is changed more than one time a day, then query should select most recent rate change for that day.
So from above table I want output like following for product id 16-
+-----------+-------------------------+------------------------+
| product_id | previous_rate | date |
+----------------+--------------------+------------------------|
| 16 | 2400 | 2016-04-30 23:05:35 |
| 16 | 4500 | 2016-04-29 11:02:42 |
+----------------+--------------------+------------------------+
I have tried following query but it returns only one row having last update rate only-
SELECT * FROM `product_rate_history` prh
INNER JOIN (SELECT max(created_on) as max FROM `product_rate_history` GROUP BY Date(created_on)) prh2
ON prh.created_on = prh2.max
WHERE prh.product_id = 16
GROUP BY DATE(prh.created_on)
ORDER BY prh.created_on DESC;
First, you do not need an aggregation in the outer query.
Second, you need to repeat the WHERE clause in the subquery (for the method you are using):
SELECT prh.*
FROM product_rate_history prh INNER JOIN
(SELECT max(created_on) as maxco
FROM product_rate_history
WHERE prh.product_id = 16
GROUP BY Date(created_on)
) prh2
ON prh.created_on = prh2.maxco
WHERE prh.product_id = 16
ORDER BY prh.created_on DESC;

Mysql Agregate function to select maximum and then select minimum price within that group

I am trying to get the maximum value out of a aggregate function, and then also get the min value out of a Price column which comes back in results.
id | discount | price
1 | 60 | 656
2 | 60 | 454
3 | 60 | 222
4 | 30 | 335
5 | 30 | 333
6 | 10 | 232
So in above table, I would like to separate Minimum Price vs Highest Discount.
This is the result I should be seeing:
id | discount | price
3 | 60 | 222
5 | 30 | 333
6 | 10 | 232
As you can see, its taken discount=60 group and separated the lowest price - 222, and the same for all other discount groups.
Could someone give me the SQL for this please, something like this -
SELECT MAX(discount) AS Maxdisc
, MIN(price) as MinPrice
,
FROM mytable
GROUP
BY discount
However, this doesnt separate the minimum price for each group. I think i need to join this table to itself to achieve that. Also, the table contains milions of rows, so the sql needs to be fast. One flat table.
This question is asked and answered with tedious regularity in SO. If only the algorithm was better at spotting duplicates. Anyway...
SELECT x.*
FROM my_table x
JOIN
( SELECT discount,MIN(price) min_price FROM my_table GROUP BY discount) y
ON y.discount = x.discount
AND y.min_price = x.price;
In your query, you cannot group by discount and then maximize the discount value.
This should get you the result you are looking for..
SELECT Max(ID) AS ID, discount, MIN(price) as MinPrice, FROM mytable GROUP BY discount
If you do not need the id, yo would do:
select discount, min(price) as minprice
from table t
group by discount;
If you want other columns in the row, you can either join back to the original table or use the substring_index()/group_concat() trick:
select substring_index(group_concat(id order by price), ',', 1) as id,
discount, min(price)
from table t
group by discount;
This will not always work because the intermediate result for group_concat() can overflow if there are too many matches within a column. This is controlled by a system parameter, which could be made bigger if necessary.

MySQL Group by week num w/ multiple date column

I have a table with columns similar to below , but with about 30 date columns and 500+ records
id | forcast_date | actual_date
1 10/01/2013 12/01/2013
2 03/01/2013 06/01/2013
3 05/01/2013 05/01/2013
4 10/01/2013 09/01/2013
and what I need to do is get a query with output similar to
week_no | count_forcast | count_actual
1 4 6
2 5 7
3 2 1
etc
My query is
SELECT weekofyear(forcast_date) as week_num,
COUNT(forcast_date) AS count_forcast ,
COUNT(actual_date) AS count_actual
FROM
table
GROUP BY
week_num
but what I am getting is the forcast_date counts repeated in each column, i.e.
week_no | count_forcast | count_actual
1 4 4
2 5 5
3 2 2
Can any one please tell me the best way to formulate the query to get what I need??
Thanks
try:
SELECT weekofyear(forcast_date) AS week_forcast,
COUNT(forcast_date) AS count_forcast, t2.count_actual
FROM
t t1 LEFT JOIN (
SELECT weekofyear(actual_date) AS week_actual,
COUNT(forcast_date) AS count_actual
FROM t
GROUP BY weekOfYear(actual_date)
) AS t2 ON weekofyear(forcast_date)=week_actual
GROUP BY
weekofyear(forcast_date), t2.count_actual
sqlFiddle
You have to write about 30 (your date columns) left join, and the requirement is that your first date column shouldn'd have empty week (with a count of 0) or the joins will miss.
Try:
SELECT WeekInYear, ForecastCount, ActualCount
FROM ( SELECT A.WeekInYear, A.ForecastCount, B.ActualCount FROM (
SELECT weekofyear(forecast_date) as WeekInYear,
COUNT(forecast_date) as ForecastCount, 0 as ActualCount
FROM TableWeeks
GROUP BY weekofyear(forecast_date)
) A
INNER JOIN
( SELECT * FROM
(
SELECT weekofyear(forecast_date) as WeekInYear,
0 as ForecastCount, COUNT(actual_date) as ActualCount
FROM TableWeeks
GROUP BY weekofyear(actual_date)
) ActualTable ) B
ON A.WeekInYear = B.WeekInYear)
AllTable
GROUP BY WeekInYear;
Here's my Fiddle Demo
Just in case someone else comes along with the same question:
Instead of trying to use some amazing query, I ended up creating an array of date_columns_names and a loop in the program that was calling this query, and for each date_column_name, performing teh asme query. It is a bit slower, but it does work

Finding an element with max. no of appearing in SQL

I have the following table:
id | year
10 | 2000
11 | 2001
10 | 2002
12 | 2003
11 | 2004
13 | 2005
10 | 2006
10 | 2007
According to id, since 10 appears most, the selection should give 10 for this table. I know this is easy but I couldn't go further than COUNT(*).
The following SQL will work when there is more then one id having the maximum count:
SELECT id FROM table GROUP BY 1
HAVING COUNT(*)=( SELECT MAX(t.count)
FROM ( SELECT id,COUNT(*) AS count
FROM table GROUP BY 1 ) t )
The first (innermost) SELECT will just count each id, this is used in the second SELECT to determine the maximum count and this will be used in the final (outermost) SELECT to display only the right IDs.
Hope that helps.
You need a group by, order by - along with a limit:
SELECT id FROM sometable GROUP BY id ORDER BY COUNT(*) DESC LIMIT 1
This will group the table by id, order them in descending order by their count and pick the first row (the one with highest count).