【问题标题】:MySQL how to select first row each group with countMySQL如何使用计数选择每个组的第一行
【发布时间】:2018-08-10 04:56:57
【问题描述】:

我有一张这样的表(简化版):

+------+-------+-----+--------------+-----+
| id   | name  | age | company.name | ...   
+------+-------+-----+--------------------+
| 1    | Adam  | 21  |  Google      | ...                  
| 3    | Peter | 20  |  Apple       | ...                 
| 2    | Bob   | 20  |  Microsoft   | ...    
| 9    | Alice | 18  |  Google      | ... 
+------+-------+-----+--------------------+

我需要按任何一列对行数进行分组。我需要在每组中获得第一行。用户选择将用于分组的列。

如果用户选择列年龄进行分组,那么结果:

+------+------------+-------+
| id   | group_name | count | 
+------+------------+-------+
| 9    | 18         |  1    |
+------+------------+-------+
| 2    | 20         |  2    |
+------+------------+-------+
| 1    | 21         |  1    |
+------+------------+-------+

要分组的列可以是数字或字符串。

目前我是通过这个查询来做的:

SELECT id, group_name, users_name, count(id) as count FROM (
 SELECT persons.id as id, company.type as group_name, users.name as users_name 
 FROM persons  
 LEFT JOIN company on company.id = persons.company_id 
 LEFT JOIN position on position.id=persons.position_id 
 ...
 LEFT JOIN source on source.id=persons.source_id 
 WHERE ...  
 ORDER BY if(company.type = '' or company.type is null,1,0) ASC,
 company.type ASC, IF(persons.status = '' or persons.status is null,1,0) ASC, 
 persons.status ASC, persons.id
) t1 GROUP BY group_name

但是对于新版本的 mysql,这个 SQL 停止工作,我认为子选择中忽略了该顺序。

我知道有人写过类似的主题,但提出的解决方案不适用于我的查询。我必须加入许多表,添加多个条件并使用级联顺序,然后从每个组中选择第一行。如果解决方案能够针对性能进行优化,我将非常高兴。

---- 编辑----

建议的解决方案: SQL select only rows with max value on a column

建议使用 MAX() 和 GROUP BY 效果不佳。有两个原因

  1. 如果分组列包含字符串,则查询返回的不是第一行,而是每组中的最后一行。
  2. 如果我的数据集有级联顺序,我不能同时在几列中使用 MAX。

我创建了包含确切示例的 sqlfiddle。

http://sqlfiddle.com/#!9/23225d/11/0

-- EXAMPLE 1 - Group by string 
-- base query
SELECT persons.*, company.* FROM persons 
LEFT JOIN company ON persons.company_id = company.id
ORDER BY company.name ASC, company.id ASC;

--   grouping query
SELECT MAX(persons.id) as id, company.name, count(persons.id) as count
FROM persons
LEFT JOIN company ON persons.company_id = company.id
GROUP BY company.name
ORDER BY company.name ASC, persons.id ASC;

-- The results will be: 
-- |ID | NAME     | COUNT|
-- |1  | Google   | 2    |
-- |3  | Microsoft| 3    |

-- EXAMPLE 2 - Cascade order
-- base query
SELECT persons.*, company.* FROM persons 
LEFT JOIN company ON persons.company_id = company.id
ORDER BY company.type ASC, persons.status ASC;

--  grouping query 
SELECT MAX(persons.id) as id, company.type, count(persons.id) as count
FROM persons
LEFT JOIN company ON persons.company_id = company.id
GROUP BY company.type
ORDER BY company.type ASC, persons.status ASC;

-- The results will be: 
-- |ID | NAME| COUNT|
-- |3  |  1  |   2  |
-- |2  |  2  |   3  |

【问题讨论】:

  • ORDER BY 从来都不是获取组第一行的正确方法。如果它以前有效,那只是偶然。
  • 我添加了解释,因为这与link不重复
  • @Barmar 我知道 ORDER BY 这样做是个坏主意,但我无法以其他方式解决这个问题。
  • 为什么不是重复的?您想获得每个组的第一行,这就是该问题显示的方法。如果您还想获取计数,只需将其添加到子查询中,以获取您订购的列的最小值。
  • 试着从那个问题中找出答案。如果您无法使其正常工作,请在此问题中发布您尝试过的内容,我会重新打开。

标签: mysql sql


【解决方案1】:

只需将MAX() 更改为MIN() 即可获取每组中的第一行而不是最后一行。

要获取级联列的极值,请参阅SQL : Using GROUP BY and MAX on multiple columns。在查询的子查询部分使用它来获取包含这些极端值的行,如SQL select only rows with max value on a column

所以完整查询的形式是:

SELECT t1.id, t1.grouped_column, t2.count
FROM yourTable AS t
JOIN (SELECT t3.grouped_column, t3.order_column1, MIN(t4.order_column2) AS order_column2, SUM(t3.count) AS count
      FROM (SELECT grouped_column, MIN(order_column1) AS order_column1, COUNT(*) AS count
            FROM yourTable
            GROUP BY grouped_column) AS t3
      JOIN yourTable AS t4 
      ON t3.grouped_column = t4.grouped_column AND t3.order_column1 = t4.order_column1
      GROUP BY t4.grouped_column, t4.order_column1) AS t2
ON t1.grouped_column = t2.grouped_column AND t1.ordered_column1 = t2.order_column1 AND t1.order_column2 = t2.order_column2

既然要对join进行操作,我建议你定义一个使用join的视图。然后,您可以在上述查询中使用该视图代替 yourTable

【讨论】:

    猜你喜欢
    • 2011-02-13
    • 2016-02-25
    • 2019-06-19
    • 1970-01-01
    • 1970-01-01
    • 2017-11-20
    • 2021-07-11
    • 2016-05-31
    相关资源
    最近更新 更多