GROUP BY没有按预期工作

时间:2013-06-28 20:39:20

标签: mysql select group-by having

我正在努力应该做一个简单的查询。

事件表在应用程序中存储用户活动。每次单击都会生成一个新事件和日期时间戳。我需要显示最近访问的记录列表,其中包含最新的日期时间戳。我只需要显示过去7天的活动。

该表有一个自动增量字段(eventID),它与date_event字段对应,因此最好使用它来确定组中的最新记录。

我发现某些记录没有出现在我的搜索结果中,而且预计最近的日期时间。所以我在基础知识中删除了我的查询:

请注意现实生活中的查询不会查看custID 。我把它包括在这里以缩小问题范围。

        SELECT
            el.eventID,
            el.custID,
            el.date_event
        FROM  
            event_log el
        WHERE 
            el.custID = 12345 AND
            el.userID=987
        GROUP BY  
            el.custID
        HAVING
            MAX( el.eventID )

返回:

eventID     custID  date_event
346290      12345   2013-06-21 09:58:44

这是EXPLAIN

id  select_type     table   type    possible_keys               key     key_len     ref     rows    Extra
1   SIMPLE          el      ref     userID,custID,Composite     custID  5           const   203     Using where

如果我将查询更改为使用HAVING MIN,结果不会改变..我应该看到不同的eventID和date_event,因为有几十条匹配custID和userID的记录。

        SELECT
            el.eventID,
            el.custID,
            el.date_event
        FROM  
            event_log el
        WHERE 
            el.custID = 12345 AND
            el.userID=987
        GROUP BY  
            el.custID
        HAVING
            MIN( el.eventID )

与之前的结果相同:

eventID     custID  date_event
346290      12345   2013-06-21 09:58:44

没有变化。

这告诉我我有另一个问题,但我没有看到可能是什么。

一些指示将不胜感激。

2 个答案:

答案 0 :(得分:3)

SELECT
    el.eventID,
    el.custID,
    el.date_event
FROM  
    event_log el
WHERE 
    el.custID = 12345 AND
    el.userID=987 AND
    el.eventID IN (SELECT MAX(eventID)
                   FROM event_log
                   WHERE custID = 12345
                   AND userID = 987)

您的查询不起作用,因为您误解了HAVING的作用。它计算结果集每一行的表达式,并将表达式计算结果的行保持为true。表达式MAX(el.eventID)只返回查询选择的最大事件ID,它不会将当前行与该事件ID进行比较。

另一种方式是:

SELECT
    el.eventID,
    el.custID,
    el.date_event
FROM  
    event_log el
WHERE 
    el.custID = 12345 AND
    el.userID=987
ORDER BY eventID DESC
LIMIT 1

适用于多个custID的更通用的表单是:

SELECT el.*
FROM event_log el
JOIN (SELECT custID, max(date_event) maxdate
      FROM event_log
      WHERE userID = 987
      GROUP BY custID) emax
ON el.custID = emax.custID AND el.date_event = emax.maxdate
WHERE el.userID = 987

答案 1 :(得分:0)

您可以在不包含GROUP BY子句的语句中使用组函数,但它等同于对所有行进行分组。但我想你正在寻找通用语法,

SELECT
  MIN(el.eventID) AS `min_eventID`, --> Yes it is wrong :(
  el.custID,
  el.date_event
FROM  
  event_log el
WHERE 
  el.userID = 987
GROUP BY el.custID;

但欢迎分歧。


[编辑]

我认为我没有足够快地展示解决方案......但也许您正在寻找最快的解决方案 假设字段 date_event 默认为CURRENT_TIMESTAMP(我错了?),按date_event排序会浪费时间(因此也是金钱)。
我用20K行做了一些测试,执行时间大约是5ms。

SELECT STRAIGHT_JOIN y.*
FROM ((
  SELECT MAX(eventId) as eventId
  FROM event_log
  WHERE userId = 987 AND custId = 12345
)) AS x
INNER JOIN event_log AS y
  USING (eventId);

也许(可能,谁知道)你没有得到直接的东西;如scriptures所述,STRAIGHT_JOIN类似于JOIN,但左表始终在右表之前读取。有时它很有用。
对于您的具体情况,我们可能会在(表“x”)之前过滤到某个eventID,而不是从表“y”中检索99,99%无用的行。

  • 3,2,...中预计会有更多分歧