MYSQL在分组之前订购

时间:2015-01-12 12:05:00

标签: mysql sql greatest-n-per-group

我有以下内容:

user_id   date_created   project_id
3         10/10/2013     1
3         09/10/2013     1
5         10/10/2013     1
8         10/10/2013     1
10        10/10/2013     1
3         08/10/2013     1

我想要的最终结果是:

user_id   date_created   project_id
3         10/10/2013     1
5         10/10/2013     1
8         10/10/2013     1
10        10/10/2013     1

上下文

我将这个东西称为影响力,用户可以对项目产生很多影响。 我想获得用户对项目的最新影响列表。

我试过了:

select * from influences 
where project_id = 1 
group by user_id
ORDER BY created_at DESC

但当然这会忽略用户创建的第一个排序,然后排序完整列表。它只是简单地搜索用户并订购结束列表


LARAVEL - 提供答案的雄辩是这样的:

return Influence::select( "user_id",  "influence", DB::raw( "MAX(created_at) as created_at" ) )
                ->where( "project_id", "=", $projectID )
                ->groupBy( "user_id", "project_id" )->get();

2 个答案:

答案 0 :(得分:4)

您不希望在group by之前订购,因为根据您的查询结构,您无需按照自己的意愿行事。

如果您想要最近创建的影响力,请明确说明:

select i.*
from influences i join
     (select user_id, max(created_at) as maxca
      from influences i
      where project_id = 1
      group by user_id
     ) iu
     on iu.user_id = i.user_id and iu.maxca = i.created_at
where i.project_id = 1;

您的意图是使用文档显式警告使用的MySQL扩展。您希望在select中添加不在group by中的列。正如documentation所说:

  

MySQL扩展了GROUP BY的使用范围,以便选择列表可以参考   未在GROUP BY子句中命名的非聚合列。这意味着   前面的查询在MySQL中是合法的。您可以使用此功能   通过避免不必要的列排序来获得更好的性能   分组。但是,这主要适用于每个中的所有值   GROUP BY中未命名的非聚合列对于每个列都是相同的   组。 服务器可以自由选择每个组中的任何值,所以   除非它们相同,否则所选择的值是不确定的。   此外,不能从每个组中选择值   受添加ORDER BY子句的影响。对结果集进行排序   选择值后发生,ORDER BY不影响   服务器选择的每个组中的值。

答案 1 :(得分:1)

使用此:

SELECT user_id, project_id, MAX(date_created) as latest
FROM influences
WHERE project_id = 1
GROUP BY user_id, project_id

工作原理:MySQL选择符合WHERE条件的所有行,然后按user_id对其进行排序,然后按user_id为每个project_id排序。从具有相同user_idproject_id的每组行中,它将在最终结果集中生成一行。

您可以在SELECT子句中使用GROUP BY子句中使用的列(user_idproject_id);它们的值是明确的:每个组中的所有行都具有相同的user_idproject_id

您也可以使用aggregate functions。它们中的每一个都使用组中所有行中的一列来计算单个值。最近的created_at当然是MAX(created_at)

如果选择既未包含在GROUP BY子句中的列,也未传递给聚合函数(如查询中的created_at),则MySQL没有提示如何计算该值。标准SQL禁止它(查询无效)但MySQL allows it。它只会从该列中选择一个值,但无法从特定行中选择它,因为这实际上是未定义的行为。

您可以省略project_id子句中的GROUP BY,因为WHERE子句会使所有行具有相同的project_id。即使project_id未出现在GROUP BY子句中并且不使用聚合函数计算,这也会巧合地使结果正确。

我建议您将project_id保留在GROUP BY子句中。它不会影响结果或查询速度,它允许您放宽过滤条件(fe使用WHERE project_id IN (1, 2))始终获得正确的结果(如果从GROUP BY中删除它,则不会发生这种情况)。