MySQL - 按非聚合列分组

问题描述 投票:0回答:1

如果我存储我的用户的分数如下:

+---------+-------+------------+
| user_id | score | created_at |
+---------+-------+------------+
|       1 |   100 | 2017-12-20 |
|       1 |   200 | 2017-12-21 |
|       2 |   110 | 2017-12-20 |
|       2 |   210 | 2017-12-21 |
|       3 |   120 | 2017-12-20 |
|       3 |   220 | 2017-12-21 |
+---------+-------+------------+

在给定输入日期的情况下,如何为每个用户获取最接近的记录?

我做得很好

SELECT *, (abs(datediff("$some-input-date", created_at))) as diff FROM table order by diff

这将给我一个输入日期2017-12-19

+---------+-------+------------+------+
| user_id | score | created_at | diff |
+---------+-------+------------+------+
|       1 |   100 | 2017-12-20 |    1 |
|       2 |   110 | 2017-12-20 |    1 |
|       3 |   120 | 2017-12-20 |    1 |
|       1 |   200 | 2017-12-21 |    2 |
|       2 |   210 | 2017-12-21 |    2 |
|       3 |   220 | 2017-12-21 |    2 |
+---------+-------+------------+------+

现在我想要user_id的独特行,所以我假设像GROUP BY user_id这样的东西可以工作,但我在MySQL 5.7中得到“SELECT列表的表达式不在GROUP BY子句中”错误。在这种情况下,我如何按user_id分组?

(我也在使用doctrine,所以如果有一些方法可以使用dql或doctrine函数来实现这一点,这也很有用)

mysql sql doctrine-orm doctrine
1个回答
2
投票

好的,所以你知道如何获得日期差异,并且你只想要特定用户的最高结果,按日期差异升序排序:

SELECT * FROM
--your current query
(SELECT *, (abs(datediff("$some-input-date", created_at))) as diff FROM table) as data_with_diffs
INNER JOIN
( --a query to find only the minimum diffs per user id
 SELECT userID, MIN(abs(datediff("$some-input-date", created_at))) as min_diff 
 FROM table 
 GROUP BY userid
) as find_min_diffs

ON 
  data_with_diffs.userid = find_min_diffs.userid AND
  data_with_diffs.diff = find_min_diffs.min_diff

如果您单独运行两个内部查询,您将看到它是如何工作的。还有其他方法来构建这个,但我认为这最适合你根据你不理解/已经开发的东西看看整个事物是如何挂起来的

分组查询仅选择特定用户ID的最小差异。通过将其作为子查询运行,并将其连接回已生成的数据,INNER JOIN将过滤掉diff不等于最小diff的所有行。

你可能仍然会为用户提供重复的行,如果他们有一个日期之前和一个日期之后有相同的差异(即-1和+1 - 这些都是最近的)所以你可能必须实施一个策略来处理它,喜欢挑选他们的MAX分数

© www.soinside.com 2019 - 2024. All rights reserved.