MySQL: после вставки триггера, инкремент переменной - PullRequest
0 голосов
/ 15 марта 2020

Как отметил П.Салмон в своем комментарии, вот краткое описание того, чего я хотел бы достичь:

У меня есть Тестирование2 татбл с двумя колонками ( проверьте пример ниже). Я регулярно делаю простую вставку, которая может выглядеть следующим образом:

INSERT INTO Testing2 (gasessiondurationbucket, gasessions) 
VALUES
(51815,20), 
(3654,18), 
(25981,28);

У меня также есть вторая таблица, в которую я хотел бы вставить однострочный журнал о всей вставке в Testing2 эта таблица называется Insert_Log_For_Testing_Tables и имеет 4 столбца (insert_id, creation_date, creation_by, ID_of_Insert). ID_of_Insert, как правило, не важен, я использовал этот столбец, чтобы протестировать некоторые из моих решений (вы можете прочитать об этом ниже).

Чего я хотел бы добиться, так это создать триггер, который будет срабатывать после каждой вставки в Testing2 и создайте единый журнал в моей таблице ( Insert_Log_For_Testing_Tables ). Так, например, после вставки с использованием запроса, приведенного выше, я хотел бы, чтобы этот триггер регистрировал это:

| insert_id | created_date          | created_by                | ID_of_Insert |
| --------- | --------------------- | ------------------------- | ------------ |
|'1'        |'2020-03-14 16:54:12'  | 'testing@IP'              |              |
| --------- | --------------------- | ------------------------- | ------------ |

Вот так будет выглядеть таблица Testing2 после этой вставки:

| gasessiondurationbucket | gasessions |
| ----------------------- | ---------- |
| '51815'                 |'20'        |
| '3654'                  |'18'        |
| '25981'                 |'28'        |
| ----------------------- | ---------- |

После другой вставки с использованием простого запроса на вставку я хотел бы создать еще один журнал в этой таблице, поэтому после двух вставок таблица Insert_Log_For_Testing_Tables будет выглядеть следующим образом:

| insert_id | created_date          | created_by                | ID_of_Insert |
| --------- | --------------------- | ------------------------- | ------------ |
|'1'        |'2020-03-14 16:54:12'  | 'testing@IP'              |              |
|'2'        |'2020-03-14 16:56:15'  | 'testing@IP'              |              |
| --------- | --------------------- | ------------------------- | ------------ |

И, например, таблица Testing2 будет выглядеть следующим образом:

| gasessiondurationbucket | gasessions |
| ----------------------- | ---------- |
| '51815'                 |'20'        |
| '3654'                  |'18'        |
| '25981'                 |'28'        |
| '96541968'              |'50'        |
| '496185'                |'48'        |
| '3168'                  |'36'        |
| '81656'                 |'55'        |
| ----------------------- | ---------- |

Есть ли способ добиться этого, используя только MySQL версия 5.7?

ниже описаны некоторые подходы, которые я пробовал, один работал, но я не думаю, что это идеальное решение, другой, к сожалению, не сделал то, что мне нужно.

"------------- -------------------------------------------------- -------------------------------------------------- ----------------- "
Я пытаюсь создать триггер, который будет срабатывать после каждой вставки в таблицу, и создать журнал в другой таблице с данные об этой вставке.

Это некоторые примеры данных из моей таблицы под названием Testing2 , в которые я регулярно вставляю данные.

| gasessiondurationbucket | gasessions |
| ----------------------- | ---------- |
| '2035',                 |'1'         |
| '1783',                 |'1'         |
| '1777',                 |'1'         |
| '1187',                 |'1'         |
| '1103',                 |'1'         |
| '811',                  |'1'         |
| '644',                  |'1'         |
| '568',                  |'1'         |
| '546',                  |'1'         |
| '435',                  |'1'         |
| '320',                  |'1'         |
| '135',                  |'1'         |
| '130',                  |'1'         |
| '65',                   |'1'         |
| '42',                   |'1'         |
| '36',                   |'1'         |
| '34',                   |'1'         |
| '21',                   |'1'         |
| '15',                   |'1'         |
| '0',                    |'19'        |
| ----------------------- | ---------- |

Это информация об этой таблице :

'CREATE TABLE `Testing2` (`gasessiondurationbucket` int(11) DEFAULT NULL,  `gasessions` int(11) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8'

Теперь вторая таблица называется Insert_Log_For_Testing_Tables и выглядит так:

| insert_id | created_date          | created_by                | ID_of_Insert |
| --------- | --------------------- | ------------------------- | ------------ |
|'1',       |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'2',       |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'3',       |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'4',       |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'5',       |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'6',       |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'7',       |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'8',       |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'9',       |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'10',      |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'11',      |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'12',      |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'13',      |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'14',      |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'15',      |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'16',      |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'17',      |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'18',      |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'19',      |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'20',      |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
| --------- | --------------------- | ------------------------- | ------------ |

Это информация об этой второй таблице:

'CREATE TABLE `Insert_Log_For_Testing_Tables` (
  `insert_id` int(11) NOT NULL AUTO_INCREMENT,
  `created_date` datetime DEFAULT NULL,
  `created_by` varchar(25) DEFAULT NULL,
  `ID_of_Insert` int(11) DEFAULT NULL,
  PRIMARY KEY (`insert_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8'

Обычно каждая вставка в первую таблицу состоит из случайного количества двух значений, то есть иногда я вставляю 20 новых значений, иногда я вставляю 100 значений.

Чего я хотел бы добиться, так это создавайте одиночный журнал, используя триггер каждый раз, когда я делаю новую вставку.

У меня проблема с FOR EACH ROW частью триггера.

Когда я пишу триггер просто так:

CREATE DEFINER=`root`@`%` TRIGGER `MyDatabase`.`Testing2_AFTER_INSERT` AFTER INSERT ON `Testing2` FOR EACH ROW
BEGIN

DECLARE vUser varchar(50);

SELECT USER() INTO vUser;

INSERT INTO Insert_Log_For_Testing_Tables
( created_date,
created_by)
VALUES
( SYSDATE(),
vUser);
END

Он работает и заполняет insert_id (автоинкремент), create_date и creation_by, но по определению он делает это для каждой новой вставленной строки, то есть я получаю несколько записей журнала (установите флажок Вставить _Log_For_Testing_Tables Table), в то время как я хотел бы только одну строку журнала. Я пришел к выводу, что я могу делать удаление после каждой вставки в журнальную таблицу на основе созданных_данных, созданных_объектов и ID_of_Insert так, чтобы это выглядело так:

CREATE DEFINER=`root`@`%` TRIGGER `MyDatabase`.`Testing2_AFTER_INSERT` AFTER INSERT ON `Testing2` FOR EACH ROW
BEGIN
DECLARE vUser varchar(50);

SELECT USER() INTO vUser;

INSERT INTO Insert_Log_For_Testing_Tables
( created_date,
created_by)
VALUES
( SYSDATE(),
vUser);

DELETE t1 FROM Insert_Log_For_Testing_Tables t1
INNER JOIN Insert_Log_For_Testing_Tables t2 
WHERE 
    t1.insert_id < t2.insert_id AND
    t1.created_date = t2.created_date AND 
    t1.created_by = t2.created_by AND
    t1.ID_of_Insert = t2.ID_of_Insert;
END

Этот триггер работает для меня и оставляет только одну запись в моя таблица журналов после каждой вставки с наибольшим номером insert_id, поэтому, когда я создаю вставку с еще 20 строками, я получаю следующий журнал:

| insert_id | created_date          | created_by                | ID_of_Insert |
| --------- | --------------------- | ------------------------- | ------------ |
|'20',      |'2020-03-14 16:54:12', | 'testing@IP',             | '2'          |
|'40',      |'2020-03-14 16:56:15', | 'testing@IP',             | '2'          |
| --------- | --------------------- | ------------------------- | ------------ |

Что мне интересно, так это то, что, поскольку я не уверен, как это работает под капотом, например, если бы мне пришлось вставить много строк в таблицу Testing2 , скажем, более миллиона, если бы create_date, в который я вставляю только SYSDATE() для каждой строки (из-за части FOR EACH ROW триггера), может отличаться для некоторых строк, то есть, когда я выполняю удаление, я могу фактически получить два журнала для одной вставки потому что столбец create_date будет содержать больше уникальных значений (первые 500000 строк будут вставлены в 2020-03-14 16:54:12, а остальные 500000 строк будут вставлены в 2020-03-14 16:54:13). Я не уверен, что это возможно, но я не хочу рисковать, поэтому я подумал, что могу попробовать что-то другое.

Мой второй подход к моей проблеме - создать два триггера (один ПЕРЕД ВСТАВКОЙ). и одна ПОСЛЕ INSERT) и одна хранимая процедура.

Теперь хранимая процедура BEFORE INSERT действительно проста и выглядит следующим образом:

CREATE DEFINER=`root`@`%` TRIGGER `MyDatabase`.`Testing2_BEFORE_INSERT` BEFORE INSERT ON `Testing2` FOR EACH ROW
BEGIN
call MyDatabase.new_procedure('1', @IDOfRow2);
END

Она просто вызывает хранимую процедуру с параметром IN, равным 1, Я делаю это только для настройки моей единственной переменной.

Моя хранимая процедура также очень проста:

CREATE DEFINER=`root`@`%` PROCEDURE `new_procedure`(IN  IDOfRow1 INT, OUT IDOfRow2 INT)
BEGIN
SELECT IDOfRow1 INTO IDOfRow2;
END

Я хочу присвоить переменной значение только 1, чтобы я мог ее использовать внутри триггера AFTER INSERT.

Триггер AFTER INSERT выглядит следующим образом:

CREATE DEFINER=`root`@`%` TRIGGER `MyDatabase`.`Testing2_AFTER_INSERT` AFTER INSERT ON `Testing2` FOR EACH ROW
BEGIN
DECLARE vUser varchar(50);

SELECT USER() INTO vUser;

SET @IDOfRow2 = @IDOfRow2 + 1;

IF @IDOfRow2 = 2 THEN
INSERT INTO Insert_Log_For_Testing_Tables
( created_date,
created_by,
ID_of_Insert)
VALUES
( SYSDATE(),
vUser,
@IDOfRow2);
END IF;

END

Я думал, что из-за этой строки: SET @IDOfRow2 = @IDOfRow2 + 1; Я мог бы изменить значение @ IDOfRow2 равно 2 и, следовательно, вставьте в таблицу Insert_Log_For_Testing_Tables только первую запись - журнал, больше ничего не будет вставлено, поскольку @ IDOfRow2 будет больше 2. Но, к сожалению, это не работает, так как, согласно исследованию, которое я провел, триггеры BEFORE INSERT для первой строки, затем триггеры AFTER INSERT для первой строки, затем триггеры BEFORE INSERT для второй строки, а затем триггеры AFTER INSERT для второй ряд et c. Это происходит для каждой строки, так что оба триггера являются своего рода альтернативой во время выполнения, что означает, что моя переменная всегда обновляется, поэтому я вставляю журнал для каждой строки, а не один для каждой вставки.

Есть ли некоторые другое решение, которое я мог бы попытаться достичь, что мне нужно, или я должен просто придерживаться инструкции DELETE внутри своего триггера AFTER UPDATE и не беспокоиться о дублированных журналах?

Я бы чувствовал себя лучше, если есть какое-то решение, подобное один с двумя триггерами и переменным, который я предложил. Есть ли какое-нибудь решение моей проблемы, или я должен придерживаться первого заявления DELETE?

Большое спасибо, если есть что-то неясное, пожалуйста, прокомментируйте, и я постараюсь уточнить.

...