MySQL按连续出现分组

3
我希望能够按照列值的连续出现对查询结果进行分组。比如说,我有一个表格列出了每年比赛的获胜者,如下所示:
year    team_name
2000    AAA
2001    CCC
2002    CCC
2003    BBB
2004    AAA
2005    AAA
2006    AAA

我想要一个查询,输出以下内容:


start_end    total   team_name
2000         1       AAA
2001-2002    2       CCC
2003         1       BBB
2004-2006    3       AAA

只要我有开始和结束或范围(例如,可以使用GROUP_CONCAT生成2004、2005、2006,而不是2004-2006,这仍然可以接受),我就不太担心“start_end”的格式。

1个回答

3
假设您的表格长这样:
"id";"year";"team"
"1";"2000";"AAA"
"2";"2001";"CCC"
"3";"2002";"CCC"
"4";"2003";"BBB"
"5";"2004";"AAA"
"6";"2005";"AAA"
"7";"2006";"AAA"

这个查询应该可以解决问题:
SELECT a.year AS start
     , MIN(c.year) AS end
     , MIN(c.year)-a.year+1 AS total
     , CONCAT_WS('-', a.year, IF(a.year = min(c.year), NULL, min(c.year))) as start_end
     , a.team
  FROM 
     ( SELECT x.year, x.team, COUNT(*) id
         FROM results x
         JOIN results y
           ON y.year <= x.year
        GROUP BY x.id
     ) AS a
  LEFT JOIN 
     ( SELECT x.year, x.team, COUNT(*) id 
         FROM results x
         JOIN results y
           ON y.year <= x.year
        GROUP BY x.id
     ) AS b ON a.id = b.id + 1 AND b.team = a.team
  LEFT JOIN  
     ( SELECT x.year, x.team, COUNT(*) id 
         FROM results x
         JOIN results y
           ON y.year <= x.year
        GROUP BY x.id
     ) AS c ON a.id <= c.id AND c.team = a.team
  LEFT JOIN 
     ( SELECT x.year, x.team, COUNT(*) id 
         FROM results x
         JOIN results y
           ON y.year <= x.year
        GROUP BY x.id
     ) AS d ON c.id = d.id - 1 AND d.team = c.team
WHERE b.id IS NULL AND c.id IS NOT NULL AND d.id IS NULL
GROUP BY start;

顺便提一下,您可能会发现常用查询树在解决这些问题时非常方便(查看“在序列中查找前一个和后一个值”的答案):p。


感谢您的快速回复。为了更容易地提出问题,我混淆了现实的某些方面:表格有一个额外的字段称为“排名”,其值如“1”、“2”、“3”,因此为了获得获胜者,需要添加“WHERE ranking = 1”的条件。如果我这样做(我将此条件添加到您查询的每个选择中),它会为每个具有相同起始和结束值(即对应年份)的年份给出获胜者。此外,总数始终等于1。由于我的数据库中有10K+条目,因此无法按原样运行您的查询。 - Max
你可以尝试创建一个仅包含获胜者记录的临时表,并在查询中使用它。我猜这样应该会加快速度...即在运行我回答中发布的查询之前,运行CREATE TEMPORARY TABLE results SELECT id, year, team FROM your_table WHERE ranking=1;。顺便说一句,如果你仍然有很多获胜者记录,你也可以向该临时表添加索引以进一步加快速度。 - wimvds
创建临时表运行良好(我添加了IF NOT EXISTS,否则在进行多个测试时会出现问题)。但是,您的查询现在在第一个子选择中失败(我将别名重命名为pinpoint),并显示“无法重新打开表:'x'”。 - Max
哎呀!是的,我忘了MySQL不允许在同一查询中多次使用临时表...你可以通过创建另一组临时表(结果的第二份副本和每个连接子查询一个临时表)来解决这个问题,或者只需创建一个带有聚合结果的常规表,运行查询并在之后删除该表(当然,对于多用户环境来说,最后一种选项并不是一个可行的解决方案)。 - wimvds
感谢您的支持。最终我将逻辑放在了PHP中,因为我需要一个即时的解决方案。 - Max
如果在给定的“团队”中年份之间存在间隙,则无法正常工作。例如,对于团队“C”,如果我们依次有2001年、2002年和2008年,则打印的是2001-2008而不是在下一行中打印2001-2002、2008。 - Kreshnik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接