Retrieving the most recent records within a query

后端 未结 3 2030
广开言路
广开言路 2020-12-15 08:15

I have the following tables:

tblPerson:

PersonID | Name
---------------------
   1     | John Smith
   2     | Jane Doe
   3     | David Hoshi
         


        
相关标签:
3条回答
  • 2020-12-15 08:46

    As @Mark Byers mentions, this problem comes up frequently on Stack Overflow.

    Here's the solution I most frequently recommend, given your tables:

    SELECT p.*, l1.*
    FROM tblPerson p
    JOIN tblLocation l1 ON p.PersonID = l1.PersonID
    LEFT OUTER JOIN tblLocation l2 ON p.PersonID = l2.PersonID AND 
      (l1.timestamp < l2.timestamp OR l1.timestamp = l2.timestamp AND l1.LocationId < l2.LocationId)
    WHERE l2.LocationID IS NULL;
    

    To see other examples, follow the tag greatest-n-per-group, which I added to your question.

    0 讨论(0)
  • 2020-12-15 08:52

    This is a classic 'max per group' question that comes up on Stack Overflow almost every day. There are many ways to solve it and you can find example solutions by searching Stack Overflow. Here is one way that you can do it in MySQL:

    SELECT
        location.LocationId,
        location.Timestamp,
        person.Name,
        location.X,
        location.Y,
        location.Z
    FROM (
        SELECT
            LocationID,
            @rn := CASE WHEN @prev_PersonID = PersonID
                        THEN @rn + 1
                        ELSE 1
                   END AS rn,
            @prev_PersonID := PersonID
        FROM (SELECT @prev_PersonID := NULL) vars, tblLocation
        ORDER BY PersonID, Timestamp DESC
    ) T1
    JOIN tblLocation location ON location.LocationID = T1.LocationId
    JOIN tblPerson person ON person.PersonID = location.PersonID
    WHERE rn = 1
    
    0 讨论(0)
  • 2020-12-15 09:10

    MySQL doesn't have ranking/analytical/windowing functionality.

    SELECT tl.locationid, tl.timestamp, tp.name, X, Y, Z
      FROM tblPerson tp
      JOIN tblLocation tl ON tl.personid = tp.personid
      JOIN (SELECT t.personid,
                   MAX(t.timestamp) AS max_date
              FROM tblLocation t
          GROUP BY t.personid) x ON x.personid = tl.personid
                                AND x.max_date = tl.timestamp
    

    SQL Server 2005+ and Oracle 9i+ support analytics, so you could use:

    SELECT x.locationid, x.timestamp, x.name, x.X, x.Y, x.Z
      FROM (SELECT tl.locationid, tl.timestamp, tp.name, X, Y, Z,
                   ROW_NUMBER() OVER (PARTITION BY tp.name ORDER BY tl.timestamp DESC) AS rank
              FROM tblPerson tp
              JOIN tblLocation tl ON tl.personid = tp.personid) x
    WHERE x.rank = 1
    

    Using a variable to get same as ROW_NUMBER functionality on MySQL:

    SELECT x.locationid, x.timestamp, x.name, x.X, x.Y, x.Z
      FROM (SELECT tl.locationid, tl.timestamp, tp.name, X, Y, Z,
                   CASE
                     WHEN @name != t.name THEN
                       @rownum := 1
                     ELSE @rownum := @rownum + 1
                   END AS rank,
                   @name := tp.name
              FROM tblLocation tl
              JOIN tblPerson tp ON tp.personid = tl.personid
              JOIN (SELECT @rownum := NULL, @name := '') r
          ORDER BY tp.name, tl.timestamp DESC) x
    WHERE x.rank = 1
    
    0 讨论(0)
提交回复
热议问题