This is a read-only copy of the MariaDB Knowledgebase generated on 2024-11-15. For the latest, interactive version please visit https://mariadb.com/kb/.

ORDER BY before GROUP BY

I have the tb_user

idnameinfo
01Petertext1
02Paultext1
03Petertext2
04Petertext3
05Paultext2

... and I need the last row of GROUP BY.

The easy SQL is:

SELECT COUNT(name), name, info FROM tb_user GROUP BY name ORDER BY id;

Tab1:

COUNT(name)nameinfo
3Petertext1
2Paultext1

But I need the LAST info!!!

Tab2:

COUNT(name)nameinfo
3Petertext3
2Paultext2

I use this SQL:

SELECT COUNT(name), name, info FROM (SELECT * FROM tb_user ORDER BY id DESC) as tb_temp GROUP BY name ;

But that's don't work!

COUNT(name)nameinfo
3Petertext1
2Paultext1

All the same:

SELECT COUNT(name), name, info FROM (SELECT * FROM tb_user ORDER BY id DESC) as tb_temp GROUP BY name ORDER BY tb_temp.id DESC;

SELECT COUNT(name), name, info FROM (SELECT * FROM tb_user ORDER BY id DESC) as tb_temp GROUP BY name  ORDER BY tb_temp.id ASC;

Who can help me? What can I do?

Answer Answered by Ian Gilfillan in this comment.

As the GROUP BY article states, "If you select a non-grouped column or a value computed from a non-grouped column, it is undefined which row the returned value is taken from. This is not permitted if the ONLY_FULL_GROUP_BY SQL_MODE is used." So you can't guarantee the order. You however use a function such as MAX(info) to get a specific value.

SELECT COUNT(name), name, MAX(info) 
 FROM tb_user GROUP BY name ORDER BY id;
+-------------+-------+-----------+
| COUNT(name) | name  | MAX(info) |
+-------------+-------+-----------+
|           3 | Peter | text3     |
|           2 | Paul  | text2     |
+-------------+-------+-----------+

Since the text is unlikely to be sortable in that way, here's an extremely horrible hack that would work, assuming your ids increment:

SELECT COUNT(name), name, MAX(CONCAT(id,': ',info)) 
 FROM tb_user GROUP BY name ORDER BY id;
+-------------+-------+---------------------------+
| COUNT(name) | name  | MAX(CONCAT(id,': ',info)) |
+-------------+-------+---------------------------+
|           3 | Peter | 4: text3                  |
|           2 | Paul  | 5: text2                  |
+-------------+-------+---------------------------+

Of course, you probably want to remove the id from the info field, so taking the hack further, and assuming the id length never exceeds 50:

SELECT COUNT(name), name, SUBSTR(MAX(CONCAT(LPAD(id,50),info)),51) AS info 
 FROM tb_user GROUP BY name ORDER BY id;
+-------------+-------+-------+
| COUNT(name) | name  | info  |
+-------------+-------+-------+
|           3 | Peter | text3 |
|           2 | Paul  | text2 |
+-------------+-------+-------+
Content reproduced on this site is the property of its respective owners, and this content is not reviewed in advance by MariaDB. The views, information and opinions expressed by this content do not necessarily represent those of MariaDB or any other party.