SQL Tip: Return only latest record by date

[edit: April 2019] This was originally posted to my internal (to Microsoft) blog on Sep 29, 2011 as part of a series I called ‘SQL Tips’ for coworkers based on an email distribution list I sent out before the internal blog. I have left this as originally written but have updated formatting for my WordPress theme. Note: there are multiple ways to do this but at the time I originally wrote this I only wrote about this one.

I’ve been asked this a couple times over the past few months and again today so I thought I’d send it out in hopes that others will benefit from this.
Consider the following:

  • You have a table that can have multiple records for a given entity (such as a machine)
  • The table has a date specifying the time of the record insert (or something like an inventory scan time)
  • You don’t want to see multiple records for a given machine; meaning, you want to only return one record per machine
  • The record you want to see is the one with the latest information (determined by the date column)

The following generalized query will allow you to do this.

SELECT  tbl.MachineName
       ,tbl.DateColumn
       ,tbl.Column3
       --,tbl….
  FROM Table1 tbl
       INNER JOIN (
                   SELECT  MachineName     AS [MachineName]
                          ,MAX(DateColumn) AS [MxDt]
                     FROM Table1
                    GROUP BY MachineName
                   ) sub
          ON tbl.MachineName = sub.MachineName
         AND tbl.DateColumn = sub.MxDt;

[edit: March 2020] Today someone reached out to ask why they couldn’t get this to work for them in their query. After looking at the sub query I noticed the issue was with the GROUP BY portion of the query. It was grouping by the date desired in the MAX aggregate. When creating an aggregate (such as MAX) you don’t want to group by the value you want to find the max of.

It also occurred to me that perhaps I should give a quick explanation of what is going on with the sample query: The sub query is written to get the max date for each entity (in this case Machine). The sub query is then joined to the same table on the entity AND the dates. This is so that you can tell SQL which record from the main table you want to retrieve.

In addition, it was suggested to have a sample query for cases when you might want to join this to other tables. So, here’s another generalized query to help explain how that could be achieved.

SELECT  tb2.MachineName
       ,tb2.ColumnTwo
       ,tbl.DateColumn
       ,tbl.ColumnN
       --,tbl….
  FROM Table2 tb2
       INNER JOIN Table1 tbl
          ON tb2.MachineName = tbl.MachineName
       INNER JOIN (
                   SELECT  MachineName     AS [MachineName]
                          ,MAX(DateColumn) AS [MxDt]
                     FROM Table1
                    GROUP BY MachineName
                   ) sub
          ON tbl.MachineName = sub.MachineName -- The original table joins on the GROUP BY column(s) AND
         AND tbl.DateColumn = sub.MxDt;        -- on the column that was aggregated

6 thoughts on “SQL Tip: Return only latest record by date

    1. That would be easy…but it wouldn’t be correct in this scenario. The reason for that is: if you add the “t.xxxx” you’ll likely get multiple records for the machinename. Which is why by first getting the machinename and it’s max date and then joining to itself you can get the correct results. Obviously, if you just needed the latest date then it would be pretty simple…well, even simpler than the example I gave. There are a few ways to achieve this, I only showed one example. Does this explanation make more sense?

      Like

      1. I put this little example together for you Doug…copy/paste this and see what I mean:

        DECLARE @Table1 table ( MachineName varchar(25) NOT NULL
        ,Column3 varchar(25) NULL
        ,DateColumn datetime NOT NULL
        );
        INSERT @Table1
        VALUES (‘MachineOne’,’some data’,’2019-08-09 20:18:31.270′),(‘MachineOne’,’somedata’,’2019-09-09 19:18:31.270′)
        ,(‘MachineOne’,’hello’,’2019-09-08 20:18:31.270′),(‘MachineOne’,’hi’,’2019-09-09 20:18:31.270′)
        ,(‘MachineTwo’,’blah’,’2019-09-09 14:34:31.270′),(‘MachineTwo’,’blah’,’2019-09-08 14:34:31.270′)
        ,(‘MachineTwo’,’blank’,’2019-09-09 03:18:31.270′),(‘MachineThree’,’Something’,’2019-09-07 15:18:31.270′)
        ,(‘MachineThree’,’Something’,’2019-09-09 15:18:31.270′);

        — Working example:
        SELECT tbl.MachineName
        ,tbl.DateColumn
        ,tbl.Column3
        FROM @Table1 tbl
        INNER JOIN (
        SELECT MachineName AS [MachineName]
        ,MAX(DateColumn) AS [MxDt]
        FROM @Table1
        GROUP BY MachineName
        ) sub
        ON tbl.MachineName = sub.MachineName
        AND tbl.DateColumn = sub.MxDt;

        — Non working example:
        SELECT MachineName
        ,MAX(DateColumn)
        ,Column3
        FROM @Table1
        GROUP BY MachineName
        ,Column3;

        Like

  1. I needed 1 record per machine for the most recent # days Visio was used from SCCM.

    I found a query to pull the last used date for SW usage from SCCM and applied what I learned above to reduce to 1 record per machine based on most recent used date.

    You would need to edit FCM.CollectionID = ‘?????????’ to which collection you want to query. ALP00014 is ‘All Workstations’ in our SCCM. Or remove this to query all collections.

    SELECT DISTINCT
    SYS.Name0 as ‘Computer’,
    exe.Publisher0 as ‘Publisher’,
    exe.ExecutableName0 as ‘Software Name’,
    abs(DATEDIFF(day,getdate(),max(usage.LastUsedTime0))) as ‘Days Since Used’

    FROM CM_ALP.dbo.v_R_System As SYS
    INNER JOIN CM_ALP.dbo.v_FullCollectionMembership FCM On FCM.ResourceID = SYS.ResourceID
    INNER JOIN CM_ALP.dbo.v_GS_INSTALLED_EXECUTABLE EXE on SYS.ResourceID = EXE.ResourceID
    INNER JOIN CM_ALP.dbo.v_GS_CCM_RECENTLY_USED_APPS Usage on SYS.ResourceID = Usage.ResourceID

    INNER JOIN (
    SELECT ResourceID as [ResourceID], MAX(Usage2.LastUsedTime0) as [MxDt]
    FROM CM_ALP.dbo.v_GS_CCM_RECENTLY_USED_APPS Usage2
    GROUP BY ResourceID
    ) sub
    ON SYS.ResourceID = sub.ResourceID AND usage.LastUsedTime0 = sub.MxDt

    WHERE
    FCM.CollectionID = ‘ALP00014’ and EXE.ExecutableName0 = ‘visio.exe’

    group by Name0, Publisher0, exe.ExecutableName0, LastUsedTime0

    Like

Leave a comment