Search code examples
mysqlgreatest-n-per-group

Issue with query greatest n per group with distinct


I have a query shown below that I would like to be able to use to show a list of the most recent change to a user. The table the records are housed in can contain multiple changes per student sometimes, but I would only like to show the most recent one per user.

For some reason, when using MAX(timestamp) it is only returning ONE user entry, and not the other users. If I remove the MAX(timestamp) It goes back to returning all records, not just one. If I add the MAX onto the timestamp back it sometimes shows only a single user change, sometimes none... Any help would be appreciated

SELECT a.* 
  FROM 
     ( SELECT 
            rID
            , r.studentID
            , oldMethod
            ,newMethod
            ,oldSubMethod
            ,newSubMethod
            ,timestamp
            ,r.staffID
            ,type
            , o.methodName oldName
            , n.methodName newName
            , s.firstName fName
            , s.lastName lName 
         FROM changeReport r
         LEFT 
         JOIN methodLookup o
           ON o.methodID = r.oldMethod
         LEFT 
         JOIN methodLookup n
           ON n.methodID = r.newMethod
         JOIN s s
           ON s.studentID = r.studentID
         LEFT 
         JOIN staffaccounts a
           ON r.staffID = a.staffID
        WHERE '$bnu' IN (newSubMethod,oldSubMethod) 
          AND DATE(timestamp) = CURRENT_DATE
     ) a
  JOIN 
     ( SELECT s.studentID
            , MAX(timestamp) timestamp
         FROM changeReport r
         LEFT 
         JOIN methodLookup o
           ON o.methodID = r.oldMethod
         LEFT 
         JOIN methodLookup n
           ON n.methodID = r.newMethod
         JOIN s s
           ON s.studentID = r.studentID
         LEFT 
         JOIN staffaccounts a
           ON r.staffID = a.staffID
        WHERE '$bnu' IN (newSubMethod,oldSubMethod) 
          AND DATE(timestamp) = CURRENT_DATE
    ) b
   ON b.studentID = a.studentID
  AND b.timestamp = a.timestamp

Solution

  • MAX, COUNT, MIN, AVG, etc are all grouping methods in MySQL.

    As such, and as a simple example, if you just

    SELECT username, MAX(date)
    FROM table
    

    you'll end up with only one result which is the one with the most recent timestamp.

    If you want to get every username with its latest update you should do:

    SELECT username, MAX(date)
    FROM table
    GROUP BY username
    

    In that way, you're being explicit about you wanting to group the query output and how do you want to group it