tags:

views:

85

answers:

2

I have the following SQL

SELECT
    Seq.UserSessionSequenceID, 
    Usr.SessionGuid, 
    Usr.UserSessionID,
    Usr.SiteID, 
    Seq.Timestamp, 
    Seq.UrlTitle, 
    Seq.Url
FROM
    tblUserSession Usr
INNER JOIN  
    tblUserSessionSequence Seq ON Usr.UserSessionID = Seq.UserSessionID
WHERE     
    (Usr.Timestamp > DATEADD(mi, -45, GETDATE())) AND (Usr.SiteID = 15)
ORDER BY Usr.Timestamp DESC

Pretty simple stuff. There are by nature multiple UserSessionIDs rows in tblUserSessionSequence. I ONLY want to return the latest (top 1) row with unique UserSessionID. How do I do that?

+4  A: 

You can use the windowing function ROW_NUMBER to number the rows for each user and select only those rows that have row number 1.

SELECT
    UserSessionSequenceID, 
    SessionGuid, 
    UserSessionID,
    SiteID, 
    Timestamp, 
    UrlTitle, 
    Url
FROM (
    SELECT
        Seq.UserSessionSequenceID, 
        Usr.SessionGuid, 
        Usr.UserSessionID,
        Usr.SiteID, 
        Usr.Timestamp AS UsrTimestamp, 
        Seq.Timestamp, 
        Seq.UrlTitle, 
        Seq.Url,
        ROW_NUMBER() OVER (PARTITION BY Usr.UserSessionID
                           ORDER BY Seq.UserSessionSequenceID DESC) AS rn
    FROM
        tblUserSession Usr
    INNER JOIN  
        tblUserSessionSequence Seq ON Usr.UserSessionID = Seq.UserSessionID
    WHERE     
        (Usr.Timestamp > DATEADD(mi, -45, GETDATE())) AND (Usr.SiteID = 15)
) T1
WHERE rn = 1
ORDER BY UsrTimestamp DESC
Mark Byers
Let me specify a bit more. I still want multiple rows in my overall result. Just only want the first unique UserSessionID's from tblUserSessionSequence
seo20
Get this error when I try to run it with the code above from you:Msg 1033, Level 15, State 1, Line 21The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.
seo20
@seo20: Try removing the order by in the subselect and see if that helps. I've updated my answer.
Mark Byers
Still getting error:Msg 102, Level 15, State 1, Line 9Incorrect syntax near ')'.Msg 102, Level 15, State 1, Line 27Incorrect syntax near 'T1'.
seo20
@seo20: There was a missing comma.
Mark Byers
Now:Msg 8156, Level 16, State 1, Line 1The column 'Timestamp' was specified multiple times for 'T1'.Msg 207, Level 16, State 1, Line 28Invalid column name 'rn'.Msg 4104, Level 16, State 1, Line 28The multi-part identifier "Seq.UserSessionSequenceID" could not be bound.Msg 4104, Level 16, State 1, Line 28The multi-part identifier "Usr.SessionGuid" could not be bound.Msg 4104, Level 16, State 1, Line 28The multi-part identifier "Usr.UserSessionID" could not be bound.Msg 4104, Level 16, State 1, Line 28The multi-part identifier "Usr.SiteID" could not be bound.Msg 4104, Level 1...
seo20
@seo20: Oops. I thought I could do this without testing since it is a very simple change but made quite a few errors, including putting the ROW_NUMBER in the outer clause instead of the inner clause! More fixes... and this time tested it.
Mark Byers
Awesome - how do I then sort it all on Usr.Timestamp DESC?
seo20
Thanks man. It works :-)
seo20
@seo20: You accepted my answer just before I changed it. Check that the updated answer is what you want, otherwise I can revert back to the previous answer.
Mark Byers
A: 

If you're looking to return only a single row in your query (i.e., the ID with the latest timestamp), just change

SELECT

to

SELECT TOP 1

If you're looking to obtain a single row for each UserSessionID, but you want to ensure that you get the one with the latest TimeStamp, that's slightly more complex.

You could do something like this:

SELECT  
    Seq.UserSessionSequenceID,   
    Usr.SessionGuid,   
    Usr.UserSessionID,  
    Usr.SiteID,   
    Seq.Timestamp,   
    Seq.UrlTitle,   
    Seq.Url  
FROM  
    tblUserSession Usr  
INNER JOIN    
    (SELECT 
        UserSessionSequenceID, 
        UserSessionID, 
        Timestamp, 
        UrlTitle, 
        Url, 
        ROW_NUMBER() over (PARTITION BY UserSessionID ORDER BY UserSessionSequenceID) AS nbr

    FROM tblUserSessionSequence) Seq ON Usr.UserSessionID = Seq.UserSessionID AND Seq.nbr = 0
WHERE       
    (Usr.Timestamp > DATEADD(mi, -45, GETDATE())) AND (Usr.SiteID = 15)  
ORDER BY Usr.Timestamp DESC 
Adam Robinson
Almost works want UserSessionID with the higest UserSessionSequenceID from tblUserSessionSequence.
seo20
@seo20: You can get whatever order you like by altering the `ORDER BY` clause inside the subselect. I've updated the answer to give what you're looking for.
Adam Robinson