简体   繁体   English

如何在MySQL中为每个组选择多行?

[英]How to select more than one row per group in MySQL?

Here is my table "puntos": 这是我的桌子“puntos”:

  Equipo      Liga  Puntos
---------------------------
 At. Madrid     1     68
 Espanyol       1     64
 Barcelona      1     63
 Real Madrid    1     61
 Castellón      1     48
 Murcia         2     78
 Elche          2     70
 Sevilla        2     60
 Valladolid     2     57

I just want to get two rows per different value of the attribute "Liga", the two that have the greatest values of "Puntos" group by "Liga". 我只想获得属性“Liga”的每个不同值的两行,这两个具有“Liga”组的“Puntos”组的最大值。

So it should return something like that: 所以它应该返回类似的东西:

 Equipo      Liga  Puntos
---------------------------
 At. Madrid     1     68
 Espanyol       1     64
 Murcia         2     78
 Elche          2     70

I get the result with that query: 我得到了该查询的结果:

SELECT * FROM puntos GROUP BY Liga HAVING max(puntos) 
UNION
SELECT p1.Equipo, p1.Liga, max(p1.puntos) FROM puntos p1, (SELECT * FROM puntos GROUP BY Liga HAVING max(puntos) ORDER BY Liga,puntos DESC) p2
WHERE p1.Liga=p2.Liga AND p1.puntos<p2.puntos GROUP BY Liga
ORDER BY Liga,puntos DESC

But that solution that not works if the select values of column "puntos" are equal. 但是,如果列“puntos”的选择值相等,则该解决方案无效。

Is there any other way to do it for any value, equal or not? 有没有其他方法可以为任何价值做,无论是否相等?

First, this solution will only work if Equipo is unique across all leagues. 首先,只有当Equipo在所有联赛中都是独一无二的时候,这个解决方案才有效。 If not - you should add equipoID and use it instead. 如果不是 - 你应该添加equipoID并改为使用它。

Now, we first select the leader of each league. 现在,我们首先选择每个联赛的领导者。 Then create a union with the same select again, only using the WHERE to filter out the teams that we've already got on our first union. 然后再次创建一个具有相同选择的联合,只使用WHERE过滤掉我们在第一个联合上已经获得的团队。 That will essentially give us the follower. 这基本上会给我们追随者。

Here's the query: 这是查询:

SELECT * FROM
  (SELECT * FROM puntos ORDER BY `liga`,`puntos` DESC) `leader`
GROUP BY `liga`

UNION
SELECT * FROM
  (SELECT * FROM puntos ORDER BY `liga`,`puntos` DESC) `follower`
WHERE `follower`.`equipo` NOT IN 
  (SELECT equipo FROM
    (SELECT * FROM puntos ORDER BY `liga`,`puntos` DESC) `leader`
   GROUP BY `liga`
  )
GROUP BY `liga`
ORDER BY `liga`

Get the max puntos 获得最大的puntos

SELECT Equipo, Liga, max(Puntos) Puntos FROM results GROUP BY Liga

Then remove the maximum by Liga from the points and get the maximum again 然后从点移除Liga的最大值并再次获得最大值

SELECT Equipo, Liga, max(Puntos) Puntos FROM results A 
    WHERE Puntos NOT IN 
    (SELECT max(Puntos) Puntos FROM results B 
     WHERE A.LIGA = B.LIGA 
     GROUP BY Liga)
    GROUP BY Liga

The wrap the whole select to order the columns 包装整个选择以排序列

SELECT Equipo, Liga, Puntos
FROM
(SELECT Equipo, Liga, max(Puntos) Puntos FROM results GROUP BY Liga
UNION 
SELECT Equipo, Liga, max(Puntos) Puntos FROM results A 
WHERE Puntos NOT IN 
(SELECT max(Puntos) Puntos FROM results B 
 WHERE A.LIGA = B.LIGA
 GROUP BY Liga)
GROUP BY Liga)  T
ORDER BY Liga ASC, Puntos DESC

Check the SqlFiddle . 检查SqlFiddle

Another option is to use 9.4 User-Defined Variables : 另一种选择是使用9.4用户定义的变量

SELECT
  `der`.`Equipo`,
  `der`.`Liga`,
  `der`.`Puntos` 
FROM (
  SELECT
    `p`.`Equipo`,
    `p`.`Liga`,
    `p`.`Puntos`,
    IF(@`prev_liga` != `p`.`Liga`,
        @`rownum` := 1,
        @`rownum` := @`rownum` + 1
    ) `rank`,
    @`prev_liga` := `p`.`Liga`
  FROM (
    SELECT
      `Equipo`,
      `Liga`,
      `Puntos`
    FROM `puntos`
    GROUP BY `Liga`, `Puntos`
    ORDER BY `Liga`, `Puntos` DESC   
  ) `p`, (SELECT
            @`rownum` := NULL,
            @`prev_liga` := 0) `r`
) `der`
WHERE `der`.`rank` <= 2
ORDER BY `der`.`Liga`, `der`.`rank`;

SQL Fiddle demo SQL小提琴演示

Two teams from the same "Liga" equal "Puntos": 来自同一“Liga”的两支队伍等同于“Puntos”:

SELECT
  `der`.`Equipo`,
  `der`.`Liga`,
  `der`.`Puntos` 
FROM (
  SELECT
    `p`.`Equipo`,
    `p`.`Liga`,
    `p`.`Puntos`,
    IF(@`prev_liga` != `p`.`Liga`,
        @`rownum` := 1,
        @`rownum` := @`rownum` + 1
    ) `rank`,
    @`prev_liga` := `p`.`Liga`
  FROM (
    SELECT
      `Equipo`,
      `Liga`,
      `Puntos`
    FROM `puntos`
    ORDER BY `Liga`, `Puntos` DESC   
  ) `p`, (SELECT
            @`rownum` := NULL,
            @`prev_liga` := 0) `r`
) `der`
WHERE `der`.`rank` <= 2
ORDER BY `der`.`Liga`, `der`.`rank`;

SQL Fiddle demo SQL小提琴演示

Hi there I will suggest little different approach to this problem. 嗨,我会建议这个问题的方法很少。

SET @num := 0, @liga := 0;

SELECT Equipo, Liga, Puntos
FROM (SELECT Equipo, Liga, Puntos, @num := if(@liga = Liga, @num + 1, 1) AS rowNumber,
              @liga := Liga
      FROM (SELECT Equipo, Liga, Puntos
            FROM results
            ORDER BY Liga, Puntos DESC) t1) tx
WHERE rowNumber <= 2;

Also here is SQL Fiddle to see how it's work... 这里还有SQL小提琴 ,看它是如何工作的...

And here you can take a look at one of my previous (very similar answer)! 在这里你可以看看我以前的一个(非常相似的答案)!

GL! GL!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM