如何获得包含每个分组集的最大值的行?

我见过这个问题的一些过于复杂的变体,没有一个有好的答案。我试着把最简单的例子放在一起:

给一个这样的表,有个人、组和年龄列,你如何得到每组中年龄最大的人?(一组中平局的结果应按首字母顺序排列)

Person | Group | Age
---
Bob  | 1     | 32  
Jill | 1     | 34  
Shawn| 1     | 42  
Jake | 2     | 29  
Paul | 2     | 36  
Laura| 2     | 39  

期望结果集:

Shawn | 1     | 42    
Laura | 2     | 39  

当前回答

采用排名法。

SELECT @rn :=  CASE WHEN @prev_grp <> groupa THEN 1 ELSE @rn+1 END AS rn,  
   @prev_grp :=groupa,
   person,age,groupa  
FROM   users,(SELECT @rn := 0) r        
HAVING rn=1
ORDER  BY groupa,age DESC,person

这个sql可以解释如下:

Select * from users, (Select @rn:= 0) r 按组别、年龄、个人排序 @prev_grp为空 @rn:= CASE WHEN @prev_grp <> groupa THEN 1 ELSE @rn+1 END 这是一个三个运算符的表达式 就像这样,rn= 1 if prev_grp != groupa else rn=rn+1 让rn=1过滤掉你需要的行

其他回答

你也可以试试

SELECT * FROM mytable WHERE age IN (SELECT MAX(age) FROM mytable GROUP BY `Group`) ;
SELECT o.*
FROM `Persons` o                   
  LEFT JOIN `Persons` b            
      ON o.Group = b.Group AND o.Age < b.Age
WHERE b.Age is NULL  
group by o.Group 

您可以连接一个取出MAX(Group)和Age的子查询。这个方法在大多数RDBMS中是可移植的。

SELECT t1.*
FROM yourTable t1
INNER JOIN
(
    SELECT `Group`, MAX(Age) AS max_age
    FROM yourTable
    GROUP BY `Group`
) t2
    ON t1.`Group` = t2.`Group` AND t1.Age = t2.max_age;

不确定MySQL是否有row_number函数。如果是这样,您可以使用它来获得所需的结果。在SQL Server上,你可以做类似的事情:

CREATE TABLE p
(
 person NVARCHAR(10),
 gp INT,
 age INT
);
GO
INSERT  INTO p
VALUES  ('Bob', 1, 32);
INSERT  INTO p
VALUES  ('Jill', 1, 34);
INSERT  INTO p
VALUES  ('Shawn', 1, 42);
INSERT  INTO p
VALUES  ('Jake', 2, 29);
INSERT  INTO p
VALUES  ('Paul', 2, 36);
INSERT  INTO p
VALUES  ('Laura', 2, 39);
GO

SELECT  t.person, t.gp, t.age
FROM    (
         SELECT *,
                ROW_NUMBER() OVER (PARTITION BY gp ORDER BY age DESC) row
         FROM   p
        ) t
WHERE   t.row = 1;

正确的解决方法是:

SELECT o.*
FROM `Persons` o                    # 'o' from 'oldest person in group'
  LEFT JOIN `Persons` b             # 'b' from 'bigger age'
      ON o.Group = b.Group AND o.Age < b.Age
WHERE b.Age is NULL                 # bigger age not found

工作原理:

它将o中的每一行与b中的所有行进行匹配,这些行在列Group中具有相同的值,在列Age中具有更大的值。来自o的任何行在Age列中没有其组的最大值,将匹配来自b的一行或多行。

LEFT JOIN使它匹配组中年龄最大的人(包括组中单独的人)与来自b('组中没有最大年龄')的满行null。 使用INNER JOIN会使这些行不匹配,它们会被忽略。

WHERE子句只保留从b中提取的字段中有null的行。它们是每个组中年龄最大的人。

进一步的阅读

这个解决方案和其他许多解决方案在《SQL反模式第1卷:避免数据库编程的陷阱》一书中有解释