MySQL-COUNT()个非聚集列

时间:2018-08-18 17:55:43

标签: mysql

相关问题:MySQL "Group By" and "Order By"

我可以使用以下查询来检索某项的下载列表:

SELECT items.id, items.name, users.fullName AS downloadedBy, dl.dateTime AS lastDownload
FROM items
    LEFT OUTER JOIN downloads dl ON dl.itemID = items.id
    LEFT JOIN users ON users.id = dl.userID
WHERE items.id = '47'
ORDER BY dl.dateTime DESC

这与预期的一样,返回下载列表,其中最新的位于顶部。

我想做的是检索该项目的上次下载和下载总数。

此查询:

SELECT items.id, items.name, users.fullName AS downloadedBy, dl.dateTime AS lastDownload, COUNT(dl.id) AS total
FROM items
    LEFT OUTER JOIN downloads dl ON dl.itemID = items.id
    LEFT JOIN users ON users.id = dl.userID
WHERE items.id = '47'
ORDER BY dl.dateTime DESC
GROUP BY items.id

返回正确的总数,但是下载详细信息(用户名和日期)是列表中间的随机条目。如链接问题中所述,将主查询包装在子查询中,然后将GROUP BY放在后面,具有相同的效果。是否可以在一个查询中同时检索上次下载和总数?

我使用的MySQL版本5.7.21禁用了ONLY_FULL_GROUP_BY

[编辑] 回答Ankit的评论:

第一个查询的输出:

id | name    | downloadedBy | lastDownload 
==============================================
47 | Item 47 | Matilda      | 2018-08-18 19:10
47 | Item 47 | Marmaduke    | 2018-08-14 07:21
47 | Item 47 | Simon        | 2018-06-11 14:02
47 | Item 47 | Boris        | 2018-06-11 14:00

所需的输出:

id | name    | downloadedBy | lastDownload     | total
======================================================
47 | Item 47 | Matilda      | 2018-08-18 19:10 | 4

第二个查询的实际输出:

id | name    | downloadedBy | lastDownload     | total
======================================================
47 | Item 47 | Simon        | 2018-06-11 14:02 | 4

1 个答案:

答案 0 :(得分:0)

您要查询的是具有独立逻辑的两个独立的事物。上一次下载查询一行,而行数计算的是行数,与上一次下载查询无关。

查询不起作用的原因是,聚合函数是根据每个常规列(id,name,fullName和dateTime)计算的。如果您未禁用ONLY_FULL_GROUP_BY,则将获得每个组合的计数。既然您已经做完了,MySQL将从这些结果集中选择随机值。禁用ONLY_FULL_GROUP_BY通常是一件坏事。它可以保护您避免错误使用GROUP BY。

要进行查询,您可以对感兴趣的两件事分别进行查询,然后将它们组合为一个。

select max(id), max(name), max(downloadedBy), max(lastDownload), max(cnt)
from (
  (SELECT items.id, items.name, users.fullName AS downloadedBy, dl.dateTime AS lastDownload
  FROM items
      LEFT OUTER JOIN downloads dl ON dl.itemID = items.id
      LEFT JOIN users ON users.id = dl.userID
  WHERE items.id = '47'
  ORDER BY dl.dateTime DESC
  limit 1)
  union
  (select null, null, null, null, count(*)
  FROM items
      LEFT OUTER JOIN downloads dl ON dl.itemID = items.id
      LEFT JOIN users ON users.id = dl.userID
  WHERE items.id = '47')
) q;