Должен ли я использовать курсоры в моей процедуре SQL? - PullRequest
1 голос
/ 15 декабря 2011

У меня есть таблица, содержащая события входа в систему и выхода из системы.Каждая строка представляет собой отдельное событие с отметкой времени, именем компьютера, кодом события входа или выхода из системы и другими подробностями.Мне нужно создать процедуру 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

Ответы [ 2 ]

2 голосов
/ 16 декабря 2011

Во-первых, ваш запрос будет проще (и быстрее), если вы сможете упорядочить данные таким образом, чтобы вам не требовался сложный подзапрос для объединения строк. Поскольку 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 голосов
/ 15 декабря 2011
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

Без какого-либо кода, над которым вы работаете ... будет трудно понять, будет ли такой подход полезным. Могут быть случаи, когда вам действительно нужно перебирать вещи ... и некоторыеслучаи, когда вместо этого можно использовать этот подход ..

[РЕДАКТИРОВАТЬ: на основе комментариев автора]

Можете ли вы попробовать выполнить это и посмотреть, если вы получите желаемые результаты?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...