我有一个包含计算机登录和注销事件的表。每行都是一个单独的事件,带有时间戳、机器名称、登录或注销事件代码和其他详细信息。我需要创建一个 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
最佳答案
首先,如果您可以按照不需要复杂子查询来配对行的方式对数据进行排序,那么您的查询将会更简单(也更快)。由于 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;
对于 future 的插入,您可以使用如下触发器来自动更新持续时间表:
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 ;
关于mysql - 我应该在 SQL 过程中使用游标吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8523183/