Sql内连接或自连接

时间:2015-05-21 13:48:37

标签: sql-server join

我有一个从程序填充的sql表,数据看起来像这样:

主键 - 请求ID 列

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

现在我需要的是

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

所以我需要我的登录信息以及同一行中的时间日志。

我怎样才能做到这一点?

我应该使用登录过滤我的第一个表,然后通过logoff或logonexpired对第二个表执行相同的操作,然后在会话ID上对这两个表进行内部联接。 ?

或者我可以在某些条件允许的情况下自行加入这些表格。

请告诉我你的建议?

嗨,

我已经提出了以下查询来获取我的登录信息以及注销时间。

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'

我在收到登录时没有收到logg时发现了一个问题,在这种情况下,即使我执行了左连接,我的表中也缺少登录记录。请让我知道我哪里出错了。

谢谢, Manikandan

3 个答案:

答案 0 :(得分:7)

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'

您已经在问题中提到了自我加入......您应该尝试一下:)

答案 1 :(得分:1)

您可以使用自我INNER JOIN轻松完成此操作,并比较sessionID和requestID。例如:

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

这已经在SQL Fiddle上进行了测试。

享受!

答案 2 :(得分:1)

如果一个会话只能有一个登录和注销事件(也就是说,如果每个登录都启动一个新会话),那么你可以完全跳过连接并使用条件选择和max()函数来展平结果: / p>

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

如果我们可以假设登录总是在注销之前发生并且总会有一对,那么你可以将它进一步减少到:

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