2015-05-21 97 views
3

我有一個程序填充一個SQL表和數據是這樣的:的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

+0

什麼版本的SQL?它可以爲這種查詢做出改變。 –

+0

...然後再按照@Joel Coehoorn,也許不是。 –

回答

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' 

你已經提到這個問題自加入...你應該嘗試一下:)

+0

只是出於好奇,爲什麼把'登錄'放在WHERE子句中,而'登錄'處於連接條件?有沒有理由不把它們放在一起? (在任一位置) – Flater

+0

非常感謝。我有以下代碼。 – ARUN

+0

@Flater這就是我關於連接的原因。對於內連接,兩個選項在功能上是等效的,但在編寫連接條件時,我傾向於考慮如何將第二個表中的記錄與第一個表中的記錄進行匹配。然後,如果我需要過濾第一個表,那麼在編寫where子句時我會看到這個過程。 –

1

您可以輕鬆地自INNER JOIN和比較要這樣做會話ID和請求ID。例如:

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上測試過。

享受!

+0

嘿。我明白使用t1.Request iD t2.request id ..是t1.requestid 代替<時,我得到重複記錄。請解釋 ARUN

+1

@RamasamyManikandan t1.requestID t2.requestID'''(這意味着如果2個ids不相等)將返回這個結果加上相同的結果相反,因此你的「重複記錄」。 –

+0

感謝您的信息。我正在使用下面的代碼並面對一些問題。請選擇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作爲LogOffTime來自[CognosAuditSampleDev] .COGIPF_USERLOGON T LEFT JOIN [CognosAuditSampleDev] .COGIPF_USERLOGON Z on T.COGIPF_SESSIONID = Z.COGIPF_SESSIONID and Z.COGIPF_LOGON_OPERATION <>'Logon'其中T.COGIPFSTATUS ='成功'和Z.COGIPFSTATUS ='成功'和T.COGIPF_LOGON_OPERATION ='登錄' – ARUN

1

如果一個會話只能有一個登錄和註銷事件(即,如果每個登錄啓動一個新的會話),那麼你可以完全跳過這個連接並使用條件選擇和max()函數來平坦化結果:

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 
+0

假設登錄總是出現在註銷之前,並且時間字段以一種理智的方式存儲,您可以進一步簡化,只需使用一個簡單的MIN()作爲LoginOperation1的RequestID和Time1字段,硬編碼「登錄」,然後使用一個簡單的MAX()用於Time2。試圖將其編輯到您的答案中。 –

+0

@JoelCoehoorn事實上,我真的沒有想太多。現在我的編輯搞砸了...... – jpw

+0

@JoelCoehoorn感謝您的編輯。 – jpw