У меня есть триггер, в котором я хочу иметь переменную, которая содержит INT, который я получаю от SELECT
, поэтому я могу использовать его в двух операторах IF вместо вызова SELECT
дважды. Как вы объявляете/используете переменные в триггерах MySQL?
MySQL Trigger - сохранение SELECT в переменной
Ответ 1
Вы можете объявлять локальные переменные в триггерах MySQL с синтаксисом DECLARE
.
Вот пример:
DROP TABLE IF EXISTS foo;
CREATE TABLE FOO (
i SERIAL PRIMARY KEY
);
DELIMITER //
DROP TRIGGER IF EXISTS bar //
CREATE TRIGGER bar AFTER INSERT ON foo
FOR EACH ROW BEGIN
DECLARE x INT;
SET x = NEW.i;
SET @a = x; -- set user variable outside trigger
END//
DELIMITER ;
SET @a = 0;
SELECT @a; -- returns 0
INSERT INTO foo () VALUES ();
SELECT @a; -- returns 1, the value it got during the trigger
Когда вы назначаете значение переменной, вы должны убедиться, что запрос возвращает только одно значение, а не набор строк или набор столбцов. Например, если ваш запрос возвращает одно значение на практике, это нормально, но как только он возвращает более одной строки, вы получаете "ERROR 1242: Subquery returns more than 1 row
".
Вы можете использовать LIMIT
или MAX()
, чтобы убедиться, что для локальной переменной установлено одно значение.
CREATE TRIGGER bar AFTER INSERT ON foo
FOR EACH ROW BEGIN
DECLARE x INT;
SET x = (SELECT age FROM users WHERE name = 'Bill');
-- ERROR 1242 if more than one row with 'Bill'
END//
CREATE TRIGGER bar AFTER INSERT ON foo
FOR EACH ROW BEGIN
DECLARE x INT;
SET x = (SELECT MAX(age) FROM users WHERE name = 'Bill');
-- OK even when more than one row with 'Bill'
END//
Ответ 2
`CREATE TRIGGER `category_before_ins_tr` BEFORE INSERT ON `category`
FOR EACH ROW
BEGIN
**SET @tableId= (SELECT id FROM dummy LIMIT 1);**
END;`;
Ответ 3
CREATE TRIGGER clearcamcdr AFTER INSERT ON `asteriskcdrdb`.`cdr`
FOR EACH ROW
BEGIN
SET @INC = (SELECT sip_inc FROM trunks LIMIT 1);
IF NEW.billsec >1 AND NEW.channel LIKE @INC
AND NEW.dstchannel NOT LIKE ""
THEN
insert into `asteriskcdrdb`.`filtre` (id_appel,date_appel,source,destinataire,duree,sens,commentaire,suivi)
values (NEW.id,NEW.calldate,NEW.src,NEW.dstchannel,NEW.billsec,"entrant","","");
END IF;
END$$
Не пытайтесь это @home
Ответ 4
Или вы можете просто включить оператор SELECT в SQL, который вызывает триггер, поэтому он прошел как один из столбцов в строке (-ах) запуска. Пока вы уверены, что он безошибочно вернет только одну строку (отсюда одно значение). (И, конечно, он не должен возвращать значение, которое взаимодействует с логикой в триггере, но это правда в любом случае.)
Ответ 5
Я отправляю это решение, потому что мне было трудно найти то, что мне нужно. Этот пост получил меня достаточно близко (+1 за это спасибо), и вот окончательное решение для переупорядочения данных столбцов перед вставкой, если данные соответствуют тесту.
Примечание: это из унаследованного проекта, унаследованного где:
- Уникальный ключ представляет собой композицию
rridprefix
+rrid
- До того, как я принял участие, не было ограничений, препятствующих дублированию уникальных ключей
- Нам нужно было объединить две таблицы (одну из дубликатов) в основную таблицу, которая теперь имеет ограничение на составной ключ (поэтому слияние не выполняется, потому что таблица выигрыша не позволит дублировать данные из нечистой таблицы)
-
on duplicate key
меньше идеального, потому что столбцы слишком многочисленны и могут меняться
В любом случае, вот триггер, который помещает любые повторяющиеся ключи в старый столбец, позволяя нам хранить устаревшие, плохие данные (а не запускать составные таблички с накоплением, уникальный ключ).. p >
BEGIN
-- prevent duplicate composite keys when merging in archive to main
SET @EXIST_COMPOSITE_KEY = (SELECT count(*) FROM patientrecords where rridprefix = NEW.rridprefix and rrid = NEW.rrid);
-- if the composite key to be introduced during merge exists, rearrange the data for insert
IF @EXIST_COMPOSITE_KEY > 0
THEN
-- set the incoming column data this way (if composite key exists)
-- the legacy duplicate rrid field will help us keep the bad data
SET NEW.legacyduperrid = NEW.rrid;
-- allow the following block to set the new rrid appropriately
SET NEW.rrid = null;
END IF;
-- legacy code tried set the rrid (race condition), now the db does it
SET NEW.rrid = (
SELECT if(NEW.rrid is null and NEW.legacyduperrid is null, IFNULL(MAX(rrid), 0) + 1, NEW.rrid)
FROM patientrecords
WHERE rridprefix = NEW.rridprefix
);
END