在锦标赛中打破关系(按子查询排序)

时间:2017-04-26 14:37:19

标签: mysql sql

在曲棍球结果数据库中,我有一张表格,用于存储每个游戏中每个团队的统计数据。对于每场比赛,(通常)有两个条目 - 每个队伍一个。这些条目存储了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。

3 个答案:

答案 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);