获取每组分组sql结果的最大值记录

4si2a6ki  于 2021-06-20  发布在  Mysql
关注(0)|答案(17)|浏览(786)

如何获得包含每个分组集的最大值的行?
我在这个问题上看到过一些过于复杂的变化,没有一个能给出好的答案。我试着把最简单的例子放在一起:
如果有这样一个表,其中有person、group和age列,那么您如何获得每组中最年长的人(一组中的平局应给出第一个按字母顺序排列的结果)

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
agyaoht7

agyaoht71#

正确的解决方案是:

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 使其与组中最年长的人(包括组中单独的人)匹配一行 NULL 来自 b (“组中没有最大年龄”)。
使用 INNER JOIN 使这些行不匹配并忽略它们。
这个 WHERE 子句只保留具有 NULL 在从 b . 他们是每组中年龄最大的人。

进一步阅读

在《sql反模式:避免数据库编程的陷阱》一书中解释了此解决方案和其他许多解决方案

6gpjuf90

6gpjuf902#

我的解决方案只适用于只需要检索一列的情况,但是对于我的需要,它是性能方面最好的解决方案(它只使用一个查询!):

SELECT SUBSTRING_INDEX(GROUP_CONCAT(column_x ORDER BY column_y),',',1) AS xyz,
   column_z
FROM table_name
GROUP BY column_z;

它使用groupconcat来创建一个有序的concat列表,然后我只将子字符串设置为第一个。

vawmfj5a

vawmfj5a3#

不确定mysql是否有行数函数。如果是这样,你可以用它来得到想要的结果。在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;
ippsafx7

ippsafx74#

让表名为people

select O.*              -- > O for oldest table
from people O , people T
where O.grp = T.grp and 
O.Age = 
(select max(T.age) from people T where O.grp = T.grp
  group by T.grp)
group by O.grp;
ghg1uchk

ghg1uchk5#

我不会使用组作为列名,因为它是保留字。但是,遵循sql就可以了。

SELECT a.Person, a.Group, a.Age FROM [TABLE_NAME] a
INNER JOIN 
(
  SELECT `Group`, MAX(Age) AS oldest FROM [TABLE_NAME] 
  GROUP BY `Group`
) b ON a.Group = b.Group AND a.Age = b.oldest
kmb7vmvb

kmb7vmvb6#

这就是我在mysql中获得每组n个最大行数的方法

SELECT co.id, co.person, co.country
FROM person co
WHERE (
SELECT COUNT(*)
FROM person ci
WHERE  co.country = ci.country AND co.id < ci.id
) < 1
;

工作原理:
自联接到表
分组方式 co.country = ci.country 每组n个元素由 ) < 1 所以对于3个元素-<3
获取最大值或最小值取决于: co.id < ci.id co.id<ci.id-最大值
co.id>ci.id-最小值
完整示例如下:
mysql选择每个组的n个最大值

ukqbszuj

ukqbszuj7#

with CTE as 
(select Person, 
[Group], Age, RN= Row_Number() 
over(partition by [Group] 
order by Age desc) 
from yourtable)`

`select Person, Age from CTE where RN = 1`
5ktev3wc

5ktev3wc8#

我针对sqlite(可能还有mysql)的简单解决方案:

SELECT *, MAX(age) FROM mytable GROUP BY `Group`;

但是,它在postgresql和其他一些平台中不起作用。
在postgresql中,可以使用distinct on子句:

SELECT DISTINCT ON ("group") * FROM "mytable" ORDER BY "group", "age" DESC;
qfe3c7zg

qfe3c7zg9#

axiac的解决方案最终对我最有效。然而,我有一个额外的复杂性:一个计算出的“最大值”,来自两列。
让我们用同一个例子:我想要每组中年龄最大的人。如果有同样年纪的人,就选个子最高的人。
我必须执行两次左连接才能得到这种行为:

SELECT o1.* WHERE
    (SELECT o.*
    FROM `Persons` o
    LEFT JOIN `Persons` b
    ON o.Group = b.Group AND o.Age < b.Age
    WHERE b.Age is NULL) o1
LEFT JOIN
    (SELECT o.*
    FROM `Persons` o
    LEFT JOIN `Persons` b
    ON o.Group = b.Group AND o.Age < b.Age
    WHERE b.Age is NULL) o2
ON o1.Group = o2.Group AND o1.Height < o2.Height 
WHERE o2.Height is NULL;

希望这有帮助!我想应该有更好的方法。。。

flvlnr44

flvlnr4410#

如果mytable需要id(和所有coulmns)

SELECT
    *
FROM
    mytable
WHERE
    id NOT IN (
        SELECT
            A.id
        FROM
            mytable AS A
        JOIN mytable AS B ON A. GROUP = B. GROUP
        AND A.age < B.age
    )
o2gm4chl

o2gm4chl11#

使用ctes-通用表表达式:

WITH MyCTE(MaxPKID, SomeColumn1)
AS(
SELECT MAX(a.MyTablePKID) AS MaxPKID, a.SomeColumn1
FROM MyTable1 a
GROUP BY a.SomeColumn1
  )
SELECT b.MyTablePKID, b.SomeColumn1, b.SomeColumn2 MAX(b.NumEstado)
FROM MyTable1 b
INNER JOIN MyCTE c ON c.MaxPKID = b.MyTablePKID
GROUP BY b.MyTablePKID, b.SomeColumn1, b.SomeColumn2

--Note: MyTablePKID is the PrimaryKey of MyTable
s8vozzvw

s8vozzvw12#

你也可以试试

SELECT * FROM mytable WHERE age IN (SELECT MAX(age) FROM mytable GROUP BY `Group`) ;
new9mtju

new9mtju13#

您可以针对一个子查询进行联接,该子查询将 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;
dgjrabp2

dgjrabp214#

在oracle中,下面的查询可以给出所需的结果。

SELECT group,person,Age,
  ROWNUMBER() OVER (PARTITION BY group ORDER BY age desc ,person asc) as rankForEachGroup
  FROM tablename where rankForEachGroup=1
k2fxgqgv

k2fxgqgv15#

这种方法的好处是允许您按不同的列进行排序,而不会破坏其他数据。在您试图用一列列出订单的情况下,它非常有用,首先列出最重的订单。
资料来源:http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-康卡特

SELECT person, group,
    GROUP_CONCAT(
        DISTINCT age
        ORDER BY age DESC SEPARATOR ', follow up: '
    )
FROM sql_table
GROUP BY group;

相关问题