2

I'm doing a query to return all the rows in table1, along with their average rating from table2:

SELECT `table1`.`description`, AVG( `table2`.`rating` ) AS avg_rating
FROM `table1` LEFT JOIN `table2` ON ( `table2`.`botid` = `table1`.`id` )
GROUP BY `table1`.`id`
ORDER BY avg_rating DESC

The problem is that even though I specify DESC, the results are being returned ASC:

+-------------+------------+
| description | avg_rating |
+-------------+------------+
| test2       |     1.0000 |
| test3       |     3.0000 |
| test4       |     3.0000 |
| saasdf      |     4.0000 |
+-------------+------------+

Why isn't MySQL honoring ORDER BY...DESC?

Even weirder, when I remove table1.description from the list of columns to retrieve, it works properly:

SELECT AVG( `table2`.`rating` ) AS avg_rating
FROM `table1` LEFT JOIN `table2` ON ( `table2`.`botid` = `table1`.`id` )
GROUP BY `table1`.`id`
ORDER BY avg_rating DESC

Returns:

+------------+
| avg_rating |
+------------+
|     4.0000 |
|     3.0000 |
|     3.0000 |
|     1.0000 |
+------------+

Here is my data:

table1:

id|description
--+-----------
 6|test2
16|test3
54|test4
72|saasdf

table2:

botid|rating
-----+------
    6|1
   16|3
   54|3
   72|4

(For the sake of this example there is a one-to-one relationship between the records in table1 and table2, but in reality there will be a one-to-many relationship.)

And my schema:

CREATE TABLE `table1` (
  `id` int(11) NOT NULL,
  `description` longtext NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `table2` (
  `botid` int(11) NOT NULL,
  `rating` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

There are indexes on both table1.id and table2.botid, although that shouldn't affect the results. I'm using MySQL 5.7.7-rc-log.

I have plenty of experience using aggregate functions, GROUP BY and ORDER BY but I've never come across anything like this. Any suggestions?

kmoser
  • 8,780
  • 3
  • 24
  • 40
  • That weird behavior is because of `longtext` type, If you can change your field type to CHAR/VARCHAR it will run perfectly. – Manoj-kr Jul 11 '17 at 07:24
  • See my answer here [Can not ORDER BY an AVG value with certain GROUP BY criteria in MySQL](https://stackoverflow.com/questions/39719785/can-not-order-by-an-avg-value-with-certain-group-by-criteria-in-mysql/39721880#39721880), there are bugs when you use `AVG` and `(long-)text` (in the question it was `group by` that column, but it's a similar problem). It's fixed in 5.7.17 (using a text-column in a non-group by-context might be fixed earlier.) – Solarflare Jul 11 '17 at 07:26
  • 1
    Your use of GROUP BY is **non-standard** although this can be permitted by MySQL depending on server settings. In particular be aware of this https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_only_full_group_by – Paul Maxwell Jul 16 '17 at 03:43

4 Answers4

3

Please upgrade to a GA version (5.7.9 was the first; 5.7.18 exists), then test again. IIRC, there was a bug somewhere in this area.

If the bug persists, provide the commands to reproduce the error and submit it to bugs.mysql.com .

I strongly recommend you change from MyISAM to InnoDB. Oracle may throw out the bug report since it involves MyISAM.

Meanwhile, you could see if this gives you the correct ordering:

SELECT  `table1`.`description`, 
        ( SELECT  AVG(`rating` )
            FROM  table2
            WHERE  botid = table1.id 
        ) AS avg_rating
    FROM  `table1`
    ORDER BY  avg_rating DESC 

Provide EXPLAIN FORMAT=JSON SELECT ... for both your version and my version.

Explanation

Your original query appears to have the "inflate-deflate" problem of JOIN ... GROUP BY. First the JOIN gathers more "rows" than you started with, then the GROUP BY shrinks it back to the original number.

My rewrite sticks to the original number of rows (in table1) and probes table 2 for the necessary stuff. Primarily (in this situation) it avoids the tmp table and filesort.

Rick James
  • 135,179
  • 13
  • 127
  • 222
  • What is the point of using subquery if join is not working.@Rick James please read this https://stackoverflow.com/questions/2577174/join-vs-sub-query – Atul Agrawal Jul 14 '17 at 13:37
  • And the link you provided is a _different_ use case. So it does not apply. – Rick James Jul 14 '17 at 16:27
2

That weird behavior is because of longtext, If you can change your field type to CHAR/VARCHAR it will run perfectly. Or try something like:

SELECT CAST(table1.desc AS CHAR(128)) AS description, AVG( table2.rating ) AS avg_rating FROM table1 LEFT JOIN table2 ON ( table2.botid = table1.id ) GROUP BY table1.id ORDER BY avg_rating DESC;

Manoj-kr
  • 776
  • 5
  • 18
  • That seems to work, but I'm wondering if this a bug or a feature in MySQL? It sure seems like a bug to me because I can't imagine any reason why the data type of a column I'm not ordering by should affect the ordering of another column. – kmoser Jul 11 '17 at 13:31
  • 2
    Yes, it is a MySql bug which got fixed in 5.7.17 release, Check: https://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-17.html – Manoj-kr Jul 12 '17 at 13:50
0

Working as expected for when run on maria db.Please check your query once because your order by is working on description column instead of avg_rating. enter image description here

You can also try

SELECT `table1`.`description`, AVG( `table2`.`rating` ) AS avg_rating FROM `table1` LEFT JOIN `table2` ON ( `table2`.`botid` = `table1`.`id` ) GROUP BY `table1`.`id` ORDER BY 2 DESC;

and check the output again.will it remain the same?

Atul Agrawal
  • 1,474
  • 5
  • 22
  • 41
  • 1
    As has been pointed out by two other people, it was caused by a bug in my version of MySQL that has since been fixed. – kmoser Jul 14 '17 at 14:17
-2

Try this one

SELECT *, AVG( table2.rating ) AS avg_rating FROM table1 INNER JOIN table2 WHERE table1.id = table2.botid GROUP BY table1.id ORDER BY table2.rating

give me. feedback