我已经浏览了几个“来自M的n”类型的解决方案,并且无法接近我所追求的内容,尽管之前可能已经问过其他格式的问题。
我已经尝试过这个MySQL Group By with top N number of each kind和http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/的例子,这些例子似乎都不适用于我正在尝试做的事情。
我要做的是确定跑步比赛中最好的球队,个别跑步者不是问题,性别,年龄类别可以照顾。团队奖项的规则基于俱乐部的会员资格。
我有一个包含以下字段的表:
+---------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| runner_id | int(11) | YES | | NULL | |
| club_id | int(11) | YES | | NULL | |
| race_id | int(11) | YES | | NULL | |
| race_number | int(11) | YES | | NULL | |
| category | varchar(20) | YES | | NULL | |
| finish_time | int(11) | YES | | NULL | |
| race_position | int(11) | YES | | NULL | |
+---------------+-------------+------+-----+---------+----------------+
只有club_id和race_position与查询相关。 runner_id,club_id和race_id是外键,我需要能够在创建结果时从这些表中提取数据(given_name,family_name,age,club_name等)。
这是典型数据:
+----+-----------+---------+---------+-------------+-----------+-------------+---------------+
| id | runner_id | club_id | race_id | race_number | category | finish_time | race_position |
+----+-----------+---------+---------+-------------+-----------+-------------+---------------+
| 53 | 26 | 1 | 85 | 17 | Msenior | 1666 | 11 |
| 35 | 39 | 1 | 85 | 4 | Munder_18 | 1503 | 4 |
| 63 | 61 | 2 | 85 | 27 | Mvet_50 | 1610 | 9 |
| 42 | 46 | 2 | 85 | 11 | Lvet_40 | 1773 | 14 |
| 38 | 42 | 2 | 85 | 7 | Lunder_18 | 1793 | 17 |
| 56 | 36 | 9 | 85 | 20 | Msenior | 1561 | 6 |
| 44 | 48 | 9 | 85 | 13 | Msenior | 1667 | 12 |
| 64 | 62 | 9 | 85 | 28 | Msenior | 1660 | 10 |
| 49 | 52 | 9 | 85 | 18 | Msenior | 1432 | 1 |
| 47 | 51 | 10 | 85 | 16 | Msenior | 1779 | 15 |
| 61 | 59 | 11 | 85 | 25 | Mvet_50 | 1502 | 3 |
| 33 | 38 | 11 | 85 | 2 | Munder_18 | 1440 | 2 |
| 65 | 63 | 11 | 85 | 29 | Mvet_40 | 1566 | 8 |
| 54 | 54 | 12 | 85 | 19 | Msenior | 1785 | 16 |
| 58 | 56 | 12 | 85 | 23 | Msenior | 1546 | 5 |
| 37 | 41 | 12 | 85 | 6 | Munder_18 | 1668 | 13 |
| 45 | 49 | 14 | 85 | 14 | Mvet_50 | 1565 | 7 |
+----+-----------+---------+---------+-------------+-----------+-------------+---------------+
我想要最终得到的是:
+----+-----------+---------+---------+-------------+-----------+-------------+---------------+
| id | runner_id | club_id | race_id | race_number | category | finish_time | race_position |
+----+-----------+---------+---------+-------------+-----------+-------------+---------------+
| 33 | 38 | 11 | 85 | 2 | Munder_18 | 1440 | 2 |
| 61 | 59 | 11 | 85 | 25 | Mvet_50 | 1502 | 3 |
| 65 | 63 | 11 | 85 | 29 | Mvet_40 | 1566 | 8 |
| 49 | 52 | 9 | 85 | 18 | Msenior | 1432 | 1 |
| 56 | 36 | 9 | 85 | 20 | Msenior | 1561 | 6 |
| 64 | 62 | 9 | 85 | 28 | Msenior | 1660 | 10 |
| 58 | 56 | 12 | 85 | 23 | Msenior | 1546 | 5 |
| 37 | 41 | 12 | 85 | 6 | Munder_18 | 1668 | 13 |
| 54 | 54 | 12 | 85 | 19 | Msenior | 1785 | 16 |
| 63 | 61 | 2 | 85 | 27 | Mvet_50 | 1610 | 9 |
| 42 | 46 | 2 | 85 | 11 | Lvet_40 | 1773 | 14 |
| 38 | 42 | 2 | 85 | 7 | Lunder_18 | 1793 | 17 |
+----+-----------+---------+---------+-------------+-----------+-------------+---------------+
所以尽管52岁的runner_id赢得了比赛,但他并没有参加胜利的球队。
我在Codeigniter / Datamapper ORM下运行所有这些,但是我可以通过这一层向下传递一个完整的SQL查询字符串。
我希望这一切都有道理。
答案 0 :(得分:0)
MySQL缺乏重要的功能来解决这个问题(CTE,窗口函数),但是您可以使用一些用户定义的变量并通过支付性能成本来解决它们:
SELECT s1.id, s1.runner_id, s1.club_id, s1.race_id, s1.race_number, s1.category,
s1.finish_time, s1.race_position
FROM (
SELECT t1.*,
@club_rank := if(@prev_club = t1.club_id, @club_rank + 1, 1) club_rank,
@prev_club := t1.club_id
FROM t t1
CROSS JOIN (SELECT @prev_club := NULL, @club_rank := 1) init
ORDER BY t1.club_id, t1.race_position
) s1
JOIN (
SELECT club_id, count(*) teamSize, sum(race_position) teamPosition FROM t
GROUP BY club_id
) s2 ON s1.club_id = s2.club_id
WHERE club_rank <= 3 AND teamSize >= 3
ORDER BY teamPosition, race_position
输出:
| ID | RUNNER_ID | CLUB_ID | RACE_ID | RACE_NUMBER | CATEGORY | FINISH_TIME | RACE_POSITION |
|----|-----------|---------|---------|-------------|-----------|-------------|---------------|
| 33 | 38 | 11 | 85 | 2 | Munder_18 | 1440 | 2 |
| 61 | 59 | 11 | 85 | 25 | Mvet_50 | 1502 | 3 |
| 65 | 63 | 11 | 85 | 29 | Mvet_40 | 1566 | 8 |
| 49 | 52 | 9 | 85 | 18 | Msenior | 1432 | 1 |
| 56 | 36 | 9 | 85 | 20 | Msenior | 1561 | 6 |
| 64 | 62 | 9 | 85 | 28 | Msenior | 1660 | 10 |
| 58 | 56 | 12 | 85 | 23 | Msenior | 1546 | 5 |
| 37 | 41 | 12 | 85 | 6 | Munder_18 | 1668 | 13 |
| 54 | 54 | 12 | 85 | 19 | Msenior | 1785 | 16 |
| 63 | 61 | 2 | 85 | 27 | Mvet_50 | 1610 | 9 |
| 42 | 46 | 2 | 85 | 11 | Lvet_40 | 1773 | 14 |
| 38 | 42 | 2 | 85 | 7 | Lunder_18 | 1793 | 17 |
小提琴here。
答案 1 :(得分:0)
有点迟,因为我不适应。
我想出了一个不太优雅的解决方案。我在表格中添加了一个club_total列。然后我循环遍历表格,每个俱乐部都有一个查询,获得前N个参赛者的查询,如:
select * from entries where race_id=? and club_id=? LIMIT ? order by race_position;
然后我忽略了那些少于N个终结者的俱乐部并将其他俱乐部的比赛位置相加并将这个值写回到桌面。
最后,我运行另一个查询,只提取那些带有总计数的行:
select * from entries where club_total > 0 and race_id=? order by club_total, race_position;
就像我说的那样,它并不优雅,而且肯定不会很快(我没有及时计算)但它只能在一台机器上每年运行几次,并且记录集是几百行一个最大值。使用小数据集时,它不会比通过AJAX显示数据的简单查询慢得多。在这种情况下完成工作比速度更重要。我不会将这种方法用于性能问题的任何情况