MySQL - 按非聚合列分组

时间:2017-12-20 09:57:22

标签: mysql sql doctrine-orm doctrine

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

+---------+-------+------------+
| 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这样的东西可以工作但我得到了一个" SELECT列表的表达式不在GROUP BY子句中#34; MySQL 5.7中的错误。如何在此方案中按user_id进行分组?

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

1 个答案:

答案 0 :(得分: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不等于最小差异的所有行

如果用户有一个日期,你可能仍会得到重复的行,如果他们有相同的差异(即-1和+1 - 这些都是最近的),那么你可能必须实施一个策略来处理就这样,就像选择他们的MAX分数一样