【发布时间】: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 效果不佳。有两个原因
- 如果分组列包含字符串,则查询返回的不是第一行,而是每组中的最后一行。
- 如果我的数据集有级联顺序,我不能同时在几列中使用 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 这样做是个坏主意,但我无法以其他方式解决这个问题。
-
为什么不是重复的?您想获得每个组的第一行,这就是该问题显示的方法。如果您还想获取计数,只需将其添加到子查询中,以获取您订购的列的最小值。
-
试着从那个问题中找出答案。如果您无法使其正常工作,请在此问题中发布您尝试过的内容,我会重新打开。