select top 5 group by and order by - mysql

I have a table like this:
CITY QNT EXP RATE
LONDON 60 6 900
LONDON 35 8 337
LONDON 24 6 300
LONDON 22 6 266
BIRMINGHAM 22 6 266
NEWYORK 69 19 263
LONDON 21 6 250
ROME 24 7 242
BIRMINGHAM 24 7 242
BIRMINGHAM 24 7 242
LONDON 20 6 233
BIRMINGHAM 23 7 228
STUTTGART 29 9 222
LONDON 19 6 216
STUTTGART 25 8 212
PARIS 31 10 210
STUTTGART 34 11 209
STUTTGART 34 11 209
BIRMINGHAM 18 6 200
BIRMINGHAM 18 6 200
NEWYORK 18 6 200
BIRMINGHAM 17 6 183
LONDON 19 7 171
MUNICH 16 6 166
PARIS 21 8 162
STUTTGART 39 15 160
BARCELONA 18 7 157
LONDON 18 7 157
ROME 33 13 153
BARCELONA 15 6 150
PARIS 25 10 150
ROME 20 8 150
PARIS 25 10 150
ROME 20 8 150
LONDON 15 6 150
MUNICH 15 6 150
BIRMINGHAM 15 6 150
NEWYORK 15 6 150
LONDON 17 7 142
MUNICH 17 7 142
Here is my sql command:
select CITY, QNT, EXP, (QNT-EXP)*100/EXP as RATE
from tbl_city
order by RATE desc
I want to group by city these results. But I couldn't do it. I want the top5 line to change most.
Result should be like that:
LONDON 60 6 900
BIRMINGHAM 22 6 266
NEWYORK 69 19 263
ROME 24 7 242
STUTTGART 29 9 222

This is from MySQL 5.6.
select CITY, QNT, EXP, (QNT-EXP)*100/EXP as RATE
from tbl_city GROUP BY CITY
order by RATE desc LIMIT 5
Tested in this link: http://www.sqlfiddle.com/#!9/3f1ea1/1
This is from MS SQL Server 2017
select TOP 5 f.CITY, f.QNT, f.EXP, x.RATE
from (
select CITY, MAX((QNT-EXP)*100/EXP) as RATE
from tbl_city GROUP BY CITY
) as x inner join tbl_city as f on f.CITY = x.CITY
and ((f.QNT-f.EXP)*100/f.EXP) = x.RATE
ORDER BY RATE DESC;
Tested in this link: http://www.sqlfiddle.com/#!18/7b8da/61

Maybe you want something like this?
select top 5 CITY, QNT, EXP, RATE
from (
select *, row_number() over (partition by CITY order by RATE desc) AS RN
from (
select CITY, QNT, EXP, (QNT-EXP)*100/EXP as RATE
from tbl_city
) X
) Y
where RN = 1
order by RATE desc
I didn't test this, but it should take first the row for the city with biggest rate, and then take top 5 rows so that that the same city is not duplicated

I don't know what is logic behind the specified formula but this does what you want
select top 5 * from (
select top(1) with ties city, qnt, exp, (qnt-exp)*100/exp as rate
from tbl_city
order by row_number() over (partition by city order by (qnt-exp)*100/exp desc)
)t
order by rate desc
However, top(1) with ties with analytical functions are available in SQL Server.

Related

Retrieve the first and second best win results per age_group column per a region column in mysql table

MySql issue: I want to extract the two best age_groups per region based on their wins. I haven't had much luck on this, having browsed similar issues. It's probably straightforward but mysql isn't playing nice for me this evening.
region
age_group
wins
london
35
52
paris
10
54
dublin
15
57
london
40
65
paris
20
68
dublin
35
73
paris
5
75
london
5
79
dublin
25
81
paris
15
81
london
30
82
dublin
20
83
london
20
85
london
10
87
london
25
87
paris
30
91
paris
25
91
dublin
40
94
dublin
30
96
dublin
5
96
london
15
99
dublin
10
100
Results should like something like this:
region
best_age_category
second_best_age_category
dublin
10
5
london
15
25
paris
25
30
select region
,group_concat(case when dns_rnk = 1 then age_group end) as best_age_category
,group_concat(case when dns_rnk = 2 then age_group end) as second_best_age_category
from (
select *
,dense_rank() over(partition by region order by wins desc) as dns_rnk
from t
) t
group by region
region
best_age_category
second_best_age_category
dublin
10
5,30
london
15
25,10
paris
30,25
15
Use ROW_NUMBER() OVER (<partition_definition> <order_definition>) to assign row numbers to your records and then filter where the row number is 1 or 2

MySQL: Get top 1 IDs

I am trying to figure out how to select the 1st property ID per client ID that gets associated to the Customer ID. Please help. How would I query this?
PropertyID ClientID CustomerID Date
10 1 35 2004
20 1 35 2004
30 2 35 2004
40 2 35 2004
50 3 35 2004
60 3 35 2004
70 4 35 2004
80 4 35 2004
90 5 35 2004
100 5 35 2004
110 6 35 2005
120 6 35 2005
130 7 35 2005
140 7 35 2005
150 8 35 2005
160 8 35 2005
170 9 35 2005
180 9 35 2005
220 15 37 2007
240 15 37 2007
260 16 37 2007
270 16 37 2007
Expected Result:
PropertyID ClientID CustomerID
10 1 35
30 2 35
50 3 35
70 4 35
90 5 35
110 6 35
130 7 35
150 8 35
170 9 35
220 15 37
260 16 37
Assuming by 1st you mean with lowest propertyId, you can use aggregation in subquery to find the lowest propertyId per clientId and then join the results with the original table to get the other corresponding columns.
select propertyId, clientId, customerId
from your_table t
join (
select clientId,
min(propertyId) as propertyId
from your_table
group by clientId
) t2 using (clientId, propertyId);
This assumes the propertyId is unique (per client at least).
Demo
SELECT MIN(PropertyID) AS PropertyID, ClientID, CustomerID
FROM table_name
GROUP BY ClientID,CustomerID;
http://sqlfiddle.com/#!9/e3dce/1
for example

mysql several column ranking per group

I have table data in this format
studno name level year term subject1 subject2 subject3
212 victor l1 2000 1 45 56 80
213 HOM l1 2000 1 42 56 70
214 ken l1 2000 1 60 70 50
215 ted l1 2000 1 46 36 47
212 victor l1 2000 2 45 36 68
213 Hom l1 2000 2 38 78 49
214 ken l1 2000 2 38 34 62
my desired output is the following
studno name level year term subject1 sub1rank subject2 sub2rank
213 victor l1 2000 1 42 3 56 2
214 HOM l1 2000 1 60 1 70 1
215 TED l1 2000 1 46 2 36 3
212 victor l1 2000 2 45 2 36 1
213 hOM l1 2000 2 38 3 36 1
214 KEN l1 2000 2 38 3 32 3
215 TED l1 2000 2 90 1 30 4
I have managed to get the rank but the problem is how to get the rank per year, level, term and subject. another problem is that if i use nested statement and try to create view in mysql database it throws an error, "View's SELECT contains a subquery in the FROM clause"
You can do this with correlated subqueries in the select clause. If I understand correctly, something like this:
select t.*,
(select COUNT(distinct t1.subject1)
from t t2
where t2.level = t.level and t2.year = t.year and t2.term = t.term and
t2.subject1 >= t.subject1
) as subj1rank,
(select COUNT(distinct t2.subject2)
from t t2
where t2.level = t.level and t2.year = t.year and t2.term = t.term and
t2.subject2 >= t.subject2
) as subj2rank
from t
The count(*) might be count(distinct subject1) (etc.), depending on how you treat ties.

SQL Count Average

I have table like
id userid semid courseid coursename total
1 36 17 13 CA 23
2 36 17 5 CB 46
3 36 17 8 CC 20
4 36 19 16 CD 34
5 36 19 13 CA 31
6 36 19 3 CA# 29
7 36 19 7 CE 60
8 36 10 9 CK 32
9 36 10 15 CH 56
I need average of semid for a userid i.e., SUM(courseid) /count (moduleid), It was showing 9 as module count, but I have only 3 modules.
This is my query
SELECT userid, SUM(total)/count(semid) FROM custom WHERE userid=36
just use the AVG( ) function
SELECT userid, semid, AVG(total)
FROM custom
WHERE userid = 36
GROUP BY userid, semid
SQLFiddle Demo
SELECT userid, SUM(total)/count(distinct semid) FROM custom WHERE userid=36
Try this query
There is MYSQL aggregate function AVG() for finding Average . #John Totet Woo has posted the answer.

Sorting varchar fields for mysql database

Trying to sort the following TEAM_TOTAL Column Desc
MATCHID TEAM_TOTAL
---------- -----------------
573 Total 112
573 Total 2 for 115
574 Total 9 for 97
574 Total 2 for 100
575 Total 9 for 129
575 Total 9 for 101
576 Total 4 for 191
576 Total 9 for 160
577 Total 8 for 157
577 Total 7 for 137
578 Total 6 for 193
578 Total 119
But the problem is TEAM_TOTAL is varchar, is there a way with query alone I can get the results in the sorted desc order.
More over there is a text as well in that column. I am running out of ideas to get this up
Result should have beeen like the below Result Set
MATCHID TEAM_TOTAL
---------- -----------------
578 Total 6 for 193
576 Total 4 for 191
576 Total 9 for 160
577 Total 8 for 157
577 Total 7 for 137
575 Total 9 for 129
578 Total 119
573 Total 2 for 115
573 Total 112
575 Total 9 for 101
574 Total 2 for 100
574 Total 9 for 97
Give this a try:
select * from t
order by substring(
team_total, locate('for', team_total) +
if(locate('for', team_total) > 0, 4, 7))+0 desc
Fiddle here.
Try to extract the integer (string after the last space):
-- 'Total 112' - extracts 112
SELECT SUBSTRING('Total 112', LENGTH('Total 112') - LOCATE(' ', REVERSE('Total 112')));
-- 'Total 6 for 193' - extracts 193
SELECT SUBSTRING('Total 6 for 193', LENGTH('Total 6 for 193') - LOCATE(' ', REVERSE('Total 6 for 193')));
Now, you can convert that string to a number and then order by it.
SELECT * FROM teams
ORDER BY
CAST(SUBSTRING(TEAM_TOTAL, LENGTH(TEAM_TOTAL) - LOCATE(' ', REVERSE(TEAM_TOTAL))) AS INT) DESC