【问题标题】:MySQL count with group by not returning correct resultMySQL 通过不返回正确结果来计算分组
【发布时间】:2016-06-23 17:55:20
【问题描述】:

我有一个票务系统,我正在尝试对其进行报告。我正在尝试获取每个用户触及的票证数量。 使用第一个查询:

SELECT * FROM (
SELECT TicketID, UserID, EventDateTime
FROM dcscontact.ticketevents
WHERE EventDateTime BETWEEN '2016-06-22' AND '2016-06-23'
ORDER BY EventDateTime DESC) x
WHERE UserID=80
GROUP BY TicketID;

我能够列出为特定用户触摸的票证,并且可以手动计算它们:

TicketID    UserID  EventDateTime
99168       80      6/22/2016 13:21
99193       80      6/22/2016 7:42
99213       80      6/22/2016 13:02
99214       80      6/22/2016 6:30
99221       80      6/22/2016 6:57
99224       80      6/22/2016 7:48
99226       80      6/22/2016 6:27
99228       80      6/22/2016 8:49
99229       80      6/22/2016 8:53
99232       80      6/22/2016 9:18
99237       80      6/22/2016 13:08

但是当我尝试删除 WHERE UserID= 语句并尝试将其用作子查询时:

SELECT UserID, COUNT(*) as count FROM (
    SELECT * FROM (
    SELECT TicketID, UserID, EventDateTime
    FROM dcscontact.ticketevents
    WHERE EventDateTime BETWEEN '2016-06-22' AND '2016-06-23'
    ORDER BY EventDateTime DESC) x
    GROUP BY TicketID) y
GROUP BY UserID;

我得到了错误的计数:

UserID  count
9       2
28      1
31      1
42      1
80      5
95      1
99      6
108     4
116     12
117     26
123     24

如您所见,UserID 80 的计数应该是 11。大多数其他结果也不正确,它们似乎都比我预期的要小。

在子查询上使用 GROUP BY/COUNT 时我做错了什么吗?如何更改我的查询以获得我想要的结果?

【问题讨论】:

  • 真的不需要重新选择与分组相同的结果。
  • 如果多个用户“触摸”同一个ticketid,你的内部查询的group by 将有效地消除这个事实;非聚合、非分组字段的值将从具有相同分组字段值的行中随机(有效)选择。

标签: mysql sql count group-by mariadb


【解决方案1】:

你只是想要一个聚合吗?

SELECT UserID, COUNT(*)
FROM dcscontact.ticketevents
WHERE EventDateTime BETWEEN '2016-06-22' AND '2016-06-23'
GROUP BY UserID;

如果给定用户的同一张票可以在数据中出现多次,则COUNT(DISTINCT)更合适:

SELECT UserID, COUNT(DISTINCT TicketID)
FROM dcscontact.ticketevents
WHERE EventDateTime BETWEEN '2016-06-22' AND '2016-06-23'
GROUP BY UserID;

【讨论】:

  • 啊,我不知道COUNT(DISTINCT),这正是我需要的。
【解决方案2】:

要获得每个用户接触的票数,让我们从一个适当的查询开始:

SELECT count(*) as N, UserID
FROM dcscontact.ticketevents
WHERE EventDateTime BETWEEN '2016-06-22' AND '2016-06-23'
GROUP BY UserID;

GROUP BY 子句应始终包含SELECT 子句中提到的所有非聚合列。询问“票证 ID 和票证数量(每个用户)”是没有意义的!

此外,SQL 标准规定 ORDER BY 不能应用于子查询。最好将ORDER BY 视为查看输出的便利,而不是用于查询的信息。

您还想了解TicketID 和EventDateTime。您不能要求“票数的id”,但您可以获得第一张和最后一张票。时间也一样:

SELECT   count(*) as N
       , min(TicketID) as T1
       , max(TicketID) as Tn
       , min(EventDateTime) as E1
       , max(EventDateTime) as En
   , UserID
FROM dcscontact.ticketevents
WHERE EventDateTime BETWEEN '2016-06-22' AND '2016-06-23'
GROUP BY UserID;

注意最早的时间可能不是TicketID最小的时间。要获取每个用户的第一张票的所有信息以及计数,请加入两个信息源:

select N.N, T.* 
from dcscontact.ticketevents as T
join (
    SELECT count(*) as N, min(TicketID) as T1, UserID
    FROM dcscontact.ticketevents
    WHERE EventDateTime BETWEEN '2016-06-22' AND '2016-06-23'
    GROUP BY UserID;
) as N
on  T.UserID = N.UserID 
and T.TicketID = N.TicketID
-- and maybe others, according to the key
order by EventDateTime DESC

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多