SQL Select last occurrence of unique attributes

sql, sql-server, sql-server-2008

Solution

SELECT  *
FROM    (
        SELECT  *,
                ROW_NUMBER() OVER (PARTITION BY attributeId ORDER BY [date] DESC) rn
        FROM    mytable
        ) q
WHERE   rn = 1

If you have a fixed list of but a few attributes (or a table with them), this query might be more efficient:

SELECT  *
FROM    attribute a
OUTER APPLY
        (
        SELECT  TOP 1
                [date], score
        FROM    score s
        WHERE   attributeId = a.id
        ORDER BY
                [date] DESC
        ) s

Create an index:

CREATE INDEX
        ix_score_attribute_date__score
ON      score (attributeId, date)
INCLUDE (score)

for this query to work fast.

Update:

To select an average of latest scores per user, use this:

SELECT  userId, AVG(score)
FROM    (
        SELECT  userId, score
        FROM    (
                SELECT  *
                        ROW_NUMBER() OVER (PARTITION BY userId, attributeId ORDER BY [date] DESC) rn
                FROM    score
                ) s
        WHERE   rn = 1
        ) q
GROUP BY
        userId

Problem

I have a table that looks like this: ``` Date | AttributeId | Score | 4/4/2013 1 0.64 4/6/2013 2 0.35 4/6/2013 1 0.86 4/4/2013 5 0.34 4/4/2013 4 0.23 4/7/2013 3 0.54 4/8/2013 1 0.66 ``` Can I construct a query in MS SQL so that I get only the last occurrence of a particular AttributeID. From example above, the query would return this: ``` Date | AttributeId | Score | 4/6/2013 2 0.35 4/4/2013 5 0.34 4/4/2013 4 0.23 4/7/2013 3 0.54 4/8/2013 1 0.66 ``` If it helps, I know that there are only 5 AttributeIDs (1-5) and that they will not change. For the moment I'm querying the last 15 records (and hoping that those records contain all of my 5 attributes), and then on the application level, extracting the latest scores for all 5 attributes. Is there a better solution? EDIT: Also, if I have `Date`, `UserId`, `AttributeId` and `Score`, can I somehow group my results by `UserId`? When I tried your answers, I saw that I only get the latest results, no matter which `UserId`. I'm sorry guys, I should have mentioned `UserId` sooner EDIT 2: I need to get the latest scores by attribute for every user and average their scores over attributes. The sample looks like this: ``` Date | UserId | AttributeId | Score | 4/4/2013 1 1 0.64 4/6/2013 1 1 0.35 4/6/2013 2 1 0.86 4/4/2013 1 3 0.34 4/4/2013 2 3 0.23 4/7/2013 2 1 0.54 4/8/2013 1 5 0.69 4/4/2013 2 4 0.27 4/7/2013 2 2 0.54 4/9/2013 1 4 0.66 4/9/2013 2 2 0.58 4/10/2013 1 4 0.66 4/9/2013 1 2 0.33 4/11/2013 2 5 0.10 ``` first result looks like this: ``` Date | UserId | AttributeId | Score | 4/6/2013 1 1 0.64 4/9/2013 1 2 0.33 4/4/2013 1 3 0.34 4/10/2013 1 4 0.66 4/8/2013 1 5 0.69 4/7/2013 2 1 0.86 4/9/2013 2 2 0.58 4/4/2013 2 3 0.23 4/4/2013 2 4 0.27 4/11/2013 2 5 0.10 ``` And the last result after averaging scores by `UserId`: ``` UserId | AverageScore | 1 0.532 2 0.408 ```

Original source