2011-12-15 45 views
1

我有一個包含計算機登錄和註銷事件的表。每一行都是一個單獨的事件,包含時間戳,機器名稱,登錄或註銷事件代碼和其他詳細信息。我需要創建一個通過此表的SQL過程,並找到相應的登錄和註銷事件,並將新行插入另一個包含計算機名稱,登錄時間,註銷時間和持續時間的表中。我應該在SQL過程中使用遊標嗎?

那麼,我應該使用一個遊標來做到這一點,或者有更好的方法來解決這個問題嗎?數據庫非常龐大,所以效率肯定是一個問題。任何建議的僞代碼都會很好。

[編輯:從評論拉到]

源表:

History (
     mc_id 
    , hs_opcode 
    , hs_time 
) 

現有數據解讀:

Login_Event = unique mc_id, hs_opcode = 1, and hs_time is the timestamp 
Logout_Event = unique mc_id, hs_opcode = 2, and hs_time is the timestamp 
+0

讓我看看我能否更清楚。我有一個名爲歷史與表mc_id,hs_opcode和hs_time表。對於登錄事件,將有唯一的mc_id,hs_opcode = 1,並且hs_time是時間戳。在註銷事件上;唯一的mc_id,hs_opcode = 2,而hs_time是時間戳。我需要處理整個表中的每個登錄事件並搜索其相應的註銷事件。所以對於註銷事件,它將是登錄事件後該機器的下一個註銷記錄; mc_id將相等,hs_opcode = 2,時間戳會更大。然後我會將它插入到新表中。 – jomille 2011-12-15 16:45:00

+0

你的問題的答案是否定的,你不應該爲此使用遊標。事實上,使用遊標可能會比下面提出的基於集合的解決方案慢得多。 – 2011-12-15 22:37:59

回答

2

首先,你的查詢會更簡單,速度更快,如果你能在這樣的,你並不需要一個複雜的子查詢配對行的方式對數據進行排序。由於MySQL不支持CTE這樣做對即時,你需要創建一個臨時表:

CREATE TABLE history_ordered (
    seq INT NOT NULL PRIMARY KEY AUTO_INCREMENT, 
    hs_id INT, 
    mc_id VARCHAR(255), 
    mc_loggedinuser VARCHAR(255), 
    hs_time DATETIME, 
    hs_opcode INT 
); 

然後,從原始表拉和排序到新表:

INSERT INTO history_ordered (
    hs_id, mc_id, mc_loggedinuser, 
    hs_time, hs_opcode) 
SELECT 
    hs_id, mc_id, mc_loggedinuser, 
    hs_time, hs_opcode 
FROM history ORDER BY mc_id, hs_time; 

現在,您可以使用此查詢到的數據關聯:

SELECT li.mc_id, 
     li.mc_loggedinuser, 
     li.hs_time as login_time, 
     lo.hs_time as logout_time 
FROM history_ordered AS li 
JOIN history_ordered AS lo 
    ON lo.seq = li.seq + 1 
    AND li.hs_opcode = 1; 

對於未來的刀片,你可以使用一個觸發類似下面,讓您的時間表自動更新:

DELIMITER $$ 
CREATE TRIGGER `match_login` AFTER INSERT ON `history` 
FOR EACH ROW 
BEGIN 
IF NEW.hs_opcode = 2 THEN 
    DECLARE _user VARCHAR(255); 
    DECLARE _login DATETIME; 
    SELECT mc_loggedinuser, hs_time FROM history 
    WHERE hs_time = (
    SELECT MAX(hs_time) FROM history 
    WHERE hs_opcode = 1 
    AND mc_id = NEW.mc_id 
) INTO _user, _login; 
    INSERT INTO login_duration 
    SET machine = NEW.mc_id, 
    logout = NEW.hs_time, 
    user = _user, 
    login = _login; 
END IF; 
END$$ 
DELIMITER ; 
2
CREATE TABLE dummy (fields you'll select data into, + additional fields as needed) 

INSERT INTO dummy (columns from your source) 
SELECT * FROM <all the tables where you need data for your target data set> 

UPDATE dummy SET col1 = CASE WHEN this = this THEN that, etc 

INSERT INTO targetTable 
SELECT all columns FROM dummy 

如果沒有你的工作的任何代碼..很難看出這種方法是否有用。可能有些情況下,您確實需要l通過空中接力的東西..而當這種方法可以用來代替某些情況下..

[編輯:根據海報的評論]

你可以嘗試執行此,看看你得到想要的結果?

INSERT INTO <your_target_table_here_with_the_three_columns_required> 
SELECT li.mc_id, li.hs_time AS login_time, lo.hs_time AS logout_time 
FROM 
    history AS li 
    INNER JOIN history AS lo 
     ON li.mc_id = lo.mc_id 
      AND li.hs_opcode = 1 
      AND lo.hs_opcode = 2 
      AND lo.hs_time = (
       SELECT min(hs_time) AS hs_time 
       FROM history 
       WHERE hs_time > li.hs_time 
       AND mc_id = li.mc_id 
      ) 
+0

這些額外的細節有幫助嗎? – jomille 2011-12-15 17:35:59

相關問題