Reputation: 31
I have an sql table populated from a program and the data would look like this:
Primary key - Request ID columns
Request ID Session ID UserID LoginOperation Time
1 1 Arun Logon 8:00
2 1 Arun Logoff 8:30
3 2 Sandy Logon 7:55
4 2 Sandy Logon Expired 8:38
Now what I need is
Request ID Session ID UserID LoginOperation Time Login Operation Time
1 1 Arun Logon 8:00 Logoff 8:30
3 2 Sandy Logon 7:55 LogonExpired 8:38
SO I will need my logon information along with the log of time in a same row.
How can I achieve this?
Should I filter my 1st table with logon and then do the same for the second table by either logoff or logonexpired and then inner join both tables on session id. ?
Or can I do a self join on these tables with some where condition..
Please let me know your suggestions?
Hi ,
I have come up with the below query to get my log on information along with the log off time.
Select T.COGIPF_LOCALTIMESTAMP, T.COGIPF_SESSIONID, T.COGIPF_REQUESTID,
T.COGIPF_STATUS, T.COGIPF_LOGON_OPERATION, T.COGIPF_USERNAME,
T.COGIPF_USERID, T.COGIPF_NAMESPACE, T.COGIPF_CAMID,
Z.COGIPF_LOCALTIMESTAMP as LogOffTime
from [CognosAuditSampleDev].COGIPF_USERLOGON T
LEFT JOIN [CognosAuditSampleDev].COGIPF_USERLOGON Z on
T.COGIPF_SESSIONID = Z.COGIPF_SESSIONID and
Z.COGIPF_LOGON_OPERATION <>'Logon'
where T.COGIPFSTATUS='Success' And Z.COGIPFSTATUS ='Success' And
T.COGIPF_LOGON_OPERATION='Logon'
I found an issue when there is no logg off received for a logon , in this case the logon record is missing in my table even after I do a left join. Please let me know where I am going wrong.
Thanks, Manikandan
Upvotes: 3
Views: 189
Reputation: 1213
You can do this easily with a self INNER JOIN
and comparing the sessionIDs and requestIDs. For example:
SELECT t1.RequestID, t1.SessionID, t1.UserID, t1.LoginOperation, t1.Time,
t2.LoginOperation, t2.Time
FROM Test t1
INNER JOIN Test t2 on t2.SessionID = t1.SessionID
WHERE t1.RequestID < t2.RequestID
This has been tested on SQL Fiddle.
Enjoy!
Upvotes: 1
Reputation: 44921
If a session only can have a single logon and logoff event (that is, if each logon starts a new session) then you could skip the join altogether and use conditional selection and the max() function to flatten the result:
SELECT
MAX(CASE WHEN LoginOperation = 'Logon' THEN RequestID END) RequestID,
SessionID, UserID,
MAX(CASE WHEN LoginOperation = 'Logon' THEN LoginOperation END) LoginOperation1,
MAX(CASE WHEN LoginOperation = 'Logon' THEN Time END) Time1,
MAX(CASE WHEN LoginOperation <> 'Logon' THEN LoginOperation END) LoginOperation2,
MAX(CASE WHEN LoginOperation <> 'Logon' THEN Time END) Time2
FROM your_table
GROUP BY SessionID, UserID
And if we can assume that logon always happens before logoff and that there will always be a pair then you could reduce it further to:
SELECT
MIN(RequestID) RequestID,
SessionID, UserID, 'Logon' as LoginOperation1,
MIN(Time) Time1,
MAX(CASE WHEN LoginOperation <> 'Logon' THEN LoginOperation END) LoginOperation2,
MAX(Time) Time2
FROM your_table
GROUP BY SessionID, UserID
Upvotes: 1
Reputation: 416131
SELECT r1.RequestID, r1.SessionID, r1.UserId, r1.LoginOperation, r1.Time
, r2.LoginOperation, r2.Time
FROM Requests r1
INNER JOIN Requests r2 on r2.SessionID = r1.SessionID and r2.LoginOperation <> 'Logon'
WHERE r1.LoginOperation = 'Logon'
You already mentioned a self-join in the question... you should just try it :)
Upvotes: 7