在曲棍球结果数据库中,我有一张表格,用于存储每个游戏中每个团队的统计数据。对于每场比赛,(通常)有两个条目 - 每个队伍一个。这些条目存储了team_id,match_id以及该比赛中球队的表现 - 获得的积分,得分和其他许多与此无关的统计数据。
以下是构建锦标赛表的近似查询:
SELECT team_id,
COUNT(match_id) AS total_matches,
SUM(goals_for) AS total_goals_for,
SUM(points) AS total_points
FROM match_teams
WHERE match_id IN ([match IDs here])
GROUP BY team_id
ORDER BY total_points DESC;
我为锦标赛中的比赛选择所有参赛作品,并为每支球队加分,然后按分数排序。
问题在于打破平局规则非常复杂。让我们考虑一下这样的规则:“如果多个团队按照这些团队之间的游戏获得的积分排列。”
因此,如果team_id IN(16,25,36)的团队的total_points相同,我应该按照以下方式对它们进行排序:
SELECT teamA.team_id,
SUM(teamA.points) AS total_points_inbetween
FROM match_teams as teamA
JOIN match_teams as teamB
ON teamA.match_id = teamB.match_id
AND teamA.team_id <> teamB.team_id
WHERE teamA.match_id IN ([match IDs here])
AND teamA.id IN (16,25,36)
AND teamB.id IN (16,25,36)
GROUP BY teamA.team_id
ORDER BY total_points_inbetween DESC;
如何在第一个查询的ORDER BY子句中包含这样的tie-breaker?我可能还需要其他规则,例如ORDER BY total_points DeSC, [complicated_rule_1], total_goals_for DESC, [complicated_rule_2]
播放以下比赛:
Match 10: team100 vs team200 2-1
Match 12: team100 vs team300 3-0
Match 15: team100 vs team400 1-2
Match 61: team100 vs team500 2-0
Match 62: team200 vs team300 5-1
Match 63: team200 vs team400 2-1
Match 66: team200 vs team500 0-3
Match 70: team300 vs team400 4-0
Match 73: team300 vs team500 5-1
Match 77: team400 vs team500 2-1
match_teams中的以下条目代表结果:
match_id team_id goals_for points
10 100 2 3
10 200 1 0
12 100 3 3
12 300 0 0
15 100 1 0
15 400 2 3
61 100 2 3
61 500 0 0
62 200 5 3
62 300 1 0
63 200 2 3
63 400 1 0
66 200 0 0
66 500 3 3
70 300 4 3
70 400 0 0
73 300 5 3
73 500 1 0
77 400 2 3
77 500 1 0
如果我们现在计算每个团队的总分(第一个查询),结果如下:
team_id total_points
100 9
200 6
300 6
400 6
500 3
中间3支球队都有相同数量的分数,因此他们之间的比赛必须打破平局。以下是:
Match 62: team200 vs team300 5-1
Match 63: team200 vs team400 2-1
Match 70: team300 vs team400 4-0
这些是数据库中相应的条目,应该考虑打破平局:
match_id team_id goals_for points
62 200 5 3
62 300 1 0
63 200 2 3
63 400 1 0
70 300 4 3
70 400 0 0
在这些球队之间的比赛中,team200获得了两场胜利(6分),team300赢得了一场比赛(3分),而team400则没有获胜。因此,他们应该使用这些点和team200&gt;进行订购。 team300&gt; team400。
答案 0 :(得分:2)
您可以将结果重用于临时表:
DROP TEMPORARY TABLE IF EXISTS tmp_match_teams;
CREATE TEMPORARY TABLE tmp_match_teams
SELECT m1.*, m2.team_id AS opponent_id
FROM match_teams m1
JOIN match_teams m2 ON m2.match_id = m1.match_id AND m2.team_id <> m1.team_id
WHERE m1.match_id IN (10,12,15,61,62,63,66,70,73,77);
DROP TEMPORARY TABLE IF EXISTS tmp_result1;
CREATE TEMPORARY TABLE tmp_result1
SELECT team_id,
COUNT(match_id) AS total_matches,
SUM(goals_for) AS total_goals_for,
SUM(points) AS total_points
FROM tmp_match_teams
GROUP BY team_id;
DROP TEMPORARY TABLE IF EXISTS tmp_result2;
CREATE TEMPORARY TABLE tmp_result2 SELECT team_id, total_points FROM tmp_result1;
SELECT r1.*, SUM(m.points) AS total_points_tie
FROM tmp_result1 r1
LEFT JOIN tmp_result2 r2
ON r2.total_points = r1.total_points
AND r2.team_id <> r1.team_id
LEFT JOIN tmp_match_teams m
ON m.team_id = r1.team_id
AND m.opponent_id = r2.team_id
GROUP BY r1.team_id
ORDER BY r1.total_points DESC, total_points_tie DESC, r1.total_goals_for DESC;
演示:http://rextester.com/HXPXRX93310
tmp_match_teams
是由锦标赛match_ids过滤的match_teams
副本,因此我们不需要多次添加该条件。它还包含oppenent_id
,我们需要加入“绑定”团队。
tmp_result1
包含原始查询的结果。
tmp_result2
包含team_id, total_points
的{{1}}副本。我们需要它在tmp_result1
上“加入”团队,我们不能在一个语句中使用相同的临时表两次(MySQL限制)。
在最后的查询中,我们“加入”具有相等total_score
的队伍以及相应的比赛,以对在这些队伍之间的比赛中收集的点数进行求和。然后在ORDER BY子句中使用该总和。您还可以添加total_score
并将其用作第四列进行排序。
如果由于某种原因无法使用临时表,则可以使用相应的子查询替换它们。然后你可能会以这样的结局结束:
SUM(goals_for) AS total_goals_tie
您还可以使用应用程序语言中存储在变量中的子查询替换临时表。例如在PHP中,它可能是这样的:
SELECT r1.*, SUM(m1.points) AS total_points_tie
FROM (
SELECT team_id,
COUNT(match_id) AS total_matches,
SUM(goals_for) AS total_goals_for,
SUM(points) AS total_points
FROM match_teams
WHERE match_id IN (10,12,15,61,62,63,66,70,73,77)
GROUP BY team_id
) r1
LEFT JOIN (
SELECT team_id, SUM(points) AS total_points
FROM match_teams
WHERE match_id IN (10,12,15,61,62,63,66,70,73,77)
GROUP BY team_id
) r2
ON r2.total_points = r1.total_points
AND r2.team_id <> r1.team_id
LEFT JOIN (
SELECT m1.team_id, m1.points, m2.team_id AS opponent_id
FROM match_teams m1
JOIN match_teams m2 ON m2.match_id = m1.match_id AND m2.team_id <> m1.team_id
WHERE m1.match_id IN (10,12,15,61,62,63,66,70,73,77)
) m1
ON m1.team_id = r1.team_id
AND m1.opponent_id = r2.team_id
GROUP BY r1.team_id
ORDER BY r1.total_points DESC, total_points_tie DESC, r1.total_goals_for DESC
答案 1 :(得分:1)
如果你真的真的需要编写一个SQL语句,大多数时候都不需要......
以下是您可以使用的复制粘贴版本。
但一定要测试和验证。我刚刚查了几个简单的案例:
select a.team_id,
sum(a.points) sort_criteria_1, /* points */
(
select sum(c.points)
from match_teams c
where c.team_id = a.team_id
and c.match_id in
(
select d.match_id
from match_teams d
where d.team_id in
(
select e.team_id
from match_teams e
where e.team_id in (select f.team_id from match_teams f group by f.team_id having sum(f.points) = sum(a.points))
and e.team_id <> a.team_id
)
)
) sort_criteria_2, /* points between */
(
select sum(c.goals_for)
from match_teams c
where c.team_id = a.team_id
and c.match_id in
(
select d.match_id
from match_teams d
where d.team_id in
(
select e.team_id
from match_teams e
where e.team_id in (select f.team_id from match_teams f group by f.team_id having sum(f.points) = sum(a.points))
and e.team_id <> a.team_id
)
)
) sort_criteria_3 /* scores between */
from match_teams a
group by a.team_id
order by sort_criteria_1 desc, sort_criteria_2 desc, sort_criteria_3 desc;
PS:是的,我讨厌编码中的大写字母。最好只利用需要强调的事物。在SQL中,没有必要将标记大写。
答案 2 :(得分:1)
首先你的查询会给出:
team_id total_points
100 9
200 6
300 6
400 6
500 3
所以你需要知道什么是拥有的球队 相同的点数来检查它们之间的匹配结果 这个查询应该这样做。
SELECT
*
FROM
(
SELECT
team_id,
COUNT(match_id) AS total_matches,
SUM(goals_for) AS total_goals_for,
SUM(points) AS total_points
FROM match_teams
-- WHERE match_id IN ([match IDs here])
GROUP BY team_id
) q1 LEFT JOIN
(
SELECT
team_id as same_ranking_team_id,
SUM(points) AS total_points
FROM match_teams
-- WHERE match_id IN ([match IDs here])
GROUP BY team_id
)q2 on q1.total_points = q2.total_points and q1.team_id != q2.same_ranking_team_id
这应该给你这个:
team_id total_points total_points same_ranking_team_id
100 9 null null
200 6 6 300
200 6 6 400
300 6 6 200
300 6 6 400
400 6 6 200
400 6 6 300
500 3 null null
现在我们需要知道的是团队之间匹配的ID 计算该匹配中的点数之和
SELECT
*
FROM
(
SELECT
team_id,
COUNT(match_id) AS total_matches,
SUM(goals_for) AS total_goals_for,
SUM(points) AS total_points
FROM match_teams
-- WHERE match_id IN ([match IDs here])
GROUP BY team_id
) q1 LEFT JOIN
(
SELECT
team_id as same_ranking_team_id,
SUM(points) AS total_points
FROM match_teams
-- WHERE match_id IN ([match IDs here])
GROUP BY team_id
)q2 on q1.total_points = q2.total_points and q1.team_id != q2.same_ranking_team_id
LEFT JOIN
(
select
match_id,
MIN(team_id) as first_team_id,
MAX(team_id) as second_team_id
from match_teams
-- WHERE match_id IN ([match IDs here])
group by match_id
) q3 on LEAST(q1.team_id, q2.same_ranking_team_id) = q3.first_team_id and GREATEST(q1.team_id, q2.same_ranking_team_id) = q3.second_team_id
这应该给你:
team_id total_points total_points same_ranking_team_id match_id frs_team scd_team
100 9 null null null null null
200 6 6 300 62 200 300
200 6 6 400 63 200 400
300 6 6 200 62 200 300
300 6 6 400 70 300 400
400 6 6 200 63 200 400
400 6 6 300 70 300 400
500 3 null null null null null
现在我们需要的是添加team_id在该匹配上得分的分数,以后可以添加goel
SELECT
*
FROM
(
SELECT
team_id,
COUNT(match_id) AS total_matches,
SUM(goals_for) AS total_goals_for,
SUM(points) AS total_points
FROM match_teams
-- WHERE match_id IN ([match IDs here])
GROUP BY team_id
) q1 LEFT JOIN
(
SELECT
team_id as same_ranking_team_id,
SUM(points) AS total_points
FROM match_teams
-- WHERE match_id IN ([match IDs here])
GROUP BY team_id
)q2 on q1.total_points = q2.total_points and q1.team_id != q2.same_ranking_team_id
LEFT JOIN
(
select
match_id,
MIN(team_id) as first_team_id,
MAX(team_id) as second_team_id
from match_teams
-- WHERE match_id IN ([match IDs here])
group by match_id
) q3 on LEAST(q1.team_id, q2.same_ranking_team_id) = q3.first_team_id and GREATEST(q1.team_id, q2.same_ranking_team_id) = q3.second_team_id
LEFT JOIN
(
select
match_id,
team_id ,
points
from match_teams
-- WHERE match_id IN ([match IDs here])
)q4 on q1.team_id = q4.team_id and q3.match_id = q4.match_id
这应该给你这个
team_id total_points total_points same_ranking_team_id match_id frs_team scd_team team_id match_id points
100 9 null null null null null null null null
200 6 6 300 62 200 300 200 62 3
200 6 6 400 63 200 400 200 63 3
300 6 6 200 62 200 300 300 62 0
300 6 6 400 70 300 400 300 70 3
400 6 6 200 63 200 400 400 63 0
400 6 6 300 70 300 400 400 70 0
500 3 null null null null null null null null
现在您拥有所有数据来对您的团队进行分类,最终查询如下:
SELECT
q1.team_id,
q1.total_points,
sum(COALESCE(q4.points, 0)) as teis_points
FROM
(
SELECT
team_id,
COUNT(match_id) AS total_matches,
SUM(goals_for) AS total_goals_for,
SUM(points) AS total_points
FROM match_teams
-- WHERE match_id IN ([match IDs here])
GROUP BY team_id
) q1 LEFT JOIN
(
SELECT
team_id as same_ranking_team_id,
SUM(points) AS total_points
FROM match_teams
-- WHERE match_id IN ([match IDs here])
GROUP BY team_id
)q2 on q1.total_points = q2.total_points and q1.team_id != q2.same_ranking_team_id
LEFT JOIN
(
select
match_id,
MIN(team_id) as first_team_id,
MAX(team_id) as second_team_id
from match_teams
-- WHERE match_id IN ([match IDs here])
group by match_id
) q3 on LEAST(q1.team_id, q2.same_ranking_team_id) = q3.first_team_id and GREATEST(q1.team_id, q2.same_ranking_team_id) = q3.second_team_id
LEFT JOIN
(
select
match_id,
team_id ,
points
from match_teams
-- WHERE match_id IN ([match IDs here])
)q4 on q1.team_id = q4.team_id and q3.match_id = q4.match_id
group by q1.team_id, q1.total_points
order by q1.total_points desc, teis_points desc
这个shoud给你
team_id total_points teis_points
100 9 0
200 6 6
300 6 3
400 6 0
500 3 0
希望我在这里没有错过任何一件事。
测试我的答案:
drop table match_teams;
create table match_teams(
match_id int,
team_id int,
goals_for int,
points int
);
insert into match_teams values
(10,100,2,3),(10,200, 1, 0),(12,100, 3, 3),
(12,300, 0, 0),(15,100, 1, 0),(15,400, 2, 3),
(61,100, 2, 3),(61,500, 0, 0),(62,200, 5, 3),
(62,300, 1, 0),(63,200, 2 ,3),(63,400, 1 ,0),
(66,200, 0 ,0),(66,500, 3 ,3),(70,300, 4 ,3),
(70,400, 0 ,0),(73,300, 5 ,3),(73,500, 1 ,0),
(77,400, 2 ,3),(77,500, 1 ,0);