2011-12-15 63 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