2

Given the following data, how would I get the desired result below?

Timestamp | Session ID | Event   | Name
------------------------------------------
08:15     | 89         | Login   | Scott
08:16     | 89         | Edit    | Scott
08:16     | 92         | Login   | John
08:17     | 92         | Refresh | John
08:23     | 89         | Logout  | Scott
08:28     | 92         | Logout  | John
08:30     | 96         | Login   | Scott
08:37     | 96         | Logout  | Scott

Desired Result (essentially a list of session durations):

Name  | Login | Logout
------------------------
Scott | 8:15  | 8:23
John  | 8:16  | 8:28
Scott | 8:30  | 8:37

edit: extended sample data and results to avoid some confusion.


The query I'm actually needing to develop is much more complex . I just thought this would give me a good jumpstart on one of the logic hurdles. Since I know everyone will want to know what I've tried, here is my current, embarrassing, iteration from the actual structure...

SELECT 
        SessionId,
        SAMLData_Organization, 
        (Select TimeCreated FROM ens.messageheader h1,HS_Message.XMLMessage m1 WHERE h1.SessionId = h3.SessionId and m1.name = 'XDSB_QueryRequest') as RequestRecieved,
        (Select TimeCreated FROM ens.messageheader h1,HS_Message.XMLMessage m1 WHERE h1.SessionId = h3.SessionId and m1.name = 'XDSB_QueryResponse') as ResponseSent
FROM 
        ens.messageheader h3,HS_Message.XMLMessage m3
WHERE SessionId IN (SELECT Distinct SessionId FROM ens.messageheader WHERE TimeCreated >= '2016-08-22 08' AND TimeCreated < '2016-08-22 17')

Things I'm trying to tackle:

  1. Join ENS.MessageHeader and HS_Message.XMLMessage
  2. Get the TimeCreated value for messages of type XDSb_QueryRequest
  3. Get the TimeCreated value for the corresponding XDSb_QueryResponse using the SessionId as a common value.
  4. Return results as Organization | RequestReceived | ResponseSent

3 Answers3

2

Pure LEFT SELF JOIN method

SELECT
    li.Name
    ,li.Timestamp as Login
    ,lo.Timestamp as LogOut
FROM
    TableName li
    LEFT JOIN TableName lo
    ON li.[Session ID] = lo.[Session ID]
    AND lo.Event = 'Logou'
WHERE
    li.Event = 'Login'

LEFT SELF JOIN with aggregation

SELECT
    li.Name
    ,li.Timestamp as Login
    ,MIN(lo.Timestamp) as LogOut
FROM
    TableName li
    LEFT JOIN TableName lo
    ON li.Name = lo.Name
    AND lo.Timestamp > li.Timestamp
    AND lo.Event = 'Logou'
WHERE
    li.Event = 'Login'
GROUP BY
    li.Name
    ,li.Timestamp

The top one is good because it constrains per SessionId so you can see a per session look. The bottom works well if session Id is not unique to the name and login/logout pair you are looking for.

Per your answer it should be able to be written like this as well:

SELECT
    li.SAMLData_Organization,
    li.SessionId,
    m1.TimeCreated as RequestRecieved,
    m2.TimeCreated as ResponseSent
FROM
    ens.messageheader h1
    INNER JOIN HS_Message.XMLMessage m1
    ON h1.MessageBodyId = m1.id
    and m1.name = 'XDSb_RetrieveRequest'
    LEFT JOIN HS_Message.XMLMessage m2
    ON h1.MessageBodyId = m2.id
    and m2.name = 'XDSb_RetrieveResponse'
ORDER BY
    h1.SessionId DESC
Matt
  • 13,833
  • 2
  • 16
  • 28
  • @Scott I am seeing comments on the other answers stating you updated your question to clarify things but have you tried the self join method yet? – Matt Aug 23 '16 at 20:40
  • I have not. I was confused until your most recent edit. I'll give it a try now. –  Aug 23 '16 at 20:42
  • yeah sorry I had merged some different methods and deleted something and I accidently left the @Table variable in the group by. I also changed the variable to TableName to make it a litter clearer. I test stuff I write with sql-server table variables.... – Matt Aug 23 '16 at 20:43
  • why not join on sessionid? – Matthew Whited Aug 23 '16 at 20:52
  • you could do that too, but because I kind of looked past it to start with reading quickly. – Matt Aug 23 '16 at 20:54
  • Yeah I'm definitely joining on session ID... still working on it. I'm having trouble since my actual `li` and `lo` tables are themselves aggregates. –  Aug 23 '16 at 21:01
  • If they themselves are aggregates you can probably do this at the first aggregation level rather than relying more than 1 level of it? If you want to update question with the more crazy real life code I would be glad to look at it and try to help. – Matt Aug 23 '16 at 21:03
  • So my result looks a bit different than yours but I think I finally got it! I posted as an answer just because, but I have accepted yours for leading me there (and likely, technically answering the sample question) –  Aug 23 '16 at 21:21
  • @Scott when you say results look different, how so? Are you getting repeated records? I see you are grouping by li.SessionId but you don't actually aggregate anything? – Matt Aug 23 '16 at 21:26
  • Sorry, poor choice of words. I meant my "resulting query". I am not getting repeated records. I'm not sure I understand your last question. Sorry, just an amateur DBA here :) –  Aug 23 '16 at 21:27
0

Based on @Matt's answer, here is my actual query:

SELECT
        li.SAMLData_Organization,
        li.SessionId,
        li.TimeCreated as RequestRecieved,
        lo.TimeCreated as ResponseSent
FROM
    (Select h1.SessionId, TimeCreated, SAMLData_Organization FROM ens.messageheader h1,HS_Message.XMLMessage m1 WHERE h1.MessageBodyId = m1.id and m1.name = 'XDSb_RetrieveRequest') li
    LEFT JOIN (Select h2.SessionId, TimeCreated FROM ens.messageheader h2,HS_Message.XMLMessage m2 WHERE h2.MessageBodyId = m2.id and m2.name = 'XDSb_RetrieveResponse') lo
    ON li.SessionId = lo.SessionId
GROUP BY li.SessionId
ORDER BY li.SessionId Desc
-2

You can do something like this, just break everything down into pieces and then put them together, I assumed you have an id column

select distinct name, id, 

(SELECT min(timestamp) from table
where event = "login" and user_id = event_table.user_id) as login,

(SELECT max (timestamp) from table
where event = "logout" and user_id = event_table.user_id) as logout

from event_table 

Hope you understand and this helps

Sobbles
  • 105
  • 1
  • 11
  • By the way I'm coming from an oracle background but the system you are using should have these basic functions – Sobbles Aug 23 '16 at 20:26
  • I updated the sample data and results, hopefully it clarifies some things. –  Aug 23 '16 at 20:34
  • You need some analytical function like a partition by used with Oracle, sorry not familiar with the system you are using. – Sobbles Aug 23 '16 at 20:41
  • @Sobbles there are at least 3 techniques without using window functions – Matt Aug 23 '16 at 20:46